This commit is contained in:
Claudio Dekker 2021-12-08 18:52:56 +01:00
parent 4636218aaa
commit e758bbf70b
No known key found for this signature in database
GPG Key ID: 6ACA8683E402B133
27 changed files with 283 additions and 229 deletions

1
.eslintrc.js vendored
View File

@ -17,6 +17,7 @@ module.exports = {
'comma-dangle': ['warn', 'always-multiline'],
'vue/multi-word-component-names': 'off',
'vue/max-attributes-per-line': 'off',
'vue/no-v-html': 'off',
'vue/require-default-prop': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/html-self-closing': [

View File

@ -3,6 +3,9 @@
"scripts": {
"dev": "npm run development",
"development": "mix",
"fix:eslint": "eslint --ext .js,.vue resources/js/ --fix",
"fix:prettier": "prettier --write --loglevel warn 'resources/js/**/*.vue'",
"fix-code-style": "npm run fix:prettier && npm run fix:eslint",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
@ -23,6 +26,8 @@
"postcss": "^8.4.4",
"postcss-import": "^12.0.1",
"postcss-nesting": "^7.0.1",
"prettier": "^2.5.1",
"prettier-plugin-tailwind": "^2.2.12",
"tailwindcss": "^2.0.3",
"uuid": "^8.3.2",
"vue": "^3.2.24",

View File

@ -1,21 +1,21 @@
<template>
<Head title="Login" />
<div class="p-6 bg-indigo-800 min-h-screen flex justify-center items-center">
<div class="flex items-center justify-center p-6 min-h-screen bg-indigo-800">
<div class="w-full max-w-md">
<logo class="block mx-auto w-full max-w-xs fill-white" height="50" />
<form class="mt-8 bg-white rounded-lg shadow-xl overflow-hidden" @submit.prevent="login">
<div class="px-10 py-12">
<h1 class="text-center font-bold text-3xl">Welcome Back!</h1>
<div class="mx-auto mt-6 w-24 border-b-2" />
<h1 class="text-center text-3xl font-bold">Welcome Back!</h1>
<div class="mt-6 mx-auto w-24 border-b-2" />
<text-input v-model="form.email" :error="form.errors.email" class="mt-10" label="Email" type="email" autofocus autocapitalize="off" />
<text-input v-model="form.password" :error="form.errors.password" class="mt-6" label="Password" type="password" />
<label class="mt-6 select-none flex items-center" for="remember">
<label class="flex items-center mt-6 select-none" for="remember">
<input id="remember" v-model="form.remember" class="mr-1" type="checkbox" />
<span class="text-sm">Remember Me</span>
</label>
</div>
<div class="px-10 py-4 bg-gray-100 border-t border-gray-100 flex">
<loading-button :loading="form.processing" class="ml-auto btn-indigo" type="submit">Login</loading-button>
<div class="flex px-10 py-4 bg-gray-100 border-t border-gray-100">
<loading-button :loading="form.processing" class="btn-indigo ml-auto" type="submit">Login</loading-button>
</div>
</form>
</div>

View File

@ -1,32 +1,32 @@
<template>
<div>
<Head title="Create Contact" />
<h1 class="mb-8 font-bold text-3xl">
<h1 class="mb-8 text-3xl font-bold">
<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">
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form @submit.prevent="store">
<div class="p-8 -mr-6 -mb-8 flex flex-wrap">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pr-6 pb-8 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pr-6 pb-8 w-full lg:w-1/2" label="Last name" />
<select-input v-model="form.organization_id" :error="form.errors.organization_id" class="pr-6 pb-8 w-full lg:w-1/2" label="Organization">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pb-8 pr-6 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pb-8 pr-6 w-full lg:w-1/2" label="Last name" />
<select-input v-model="form.organization_id" :error="form.errors.organization_id" class="pb-8 pr-6 w-full lg:w-1/2" label="Organization">
<option :value="null" />
<option v-for="organization in organizations" :key="organization.id" :value="organization.id">{{ organization.name }}</option>
</select-input>
<text-input v-model="form.email" :error="form.errors.email" class="pr-6 pb-8 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pr-6 pb-8 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pr-6 pb-8 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pr-6 pb-8 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pr-6 pb-8 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pr-6 pb-8 w-full lg:w-1/2" label="Country">
<text-input v-model="form.email" :error="form.errors.email" class="pb-8 pr-6 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pb-8 pr-6 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pb-8 pr-6 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pb-8 pr-6 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pb-8 pr-6 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pb-8 pr-6 w-full lg:w-1/2" label="Country">
<option :value="null" />
<option value="CA">Canada</option>
<option value="US">United States</option>
</select-input>
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pr-6 pb-8 w-full lg:w-1/2" label="Postal code" />
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pb-8 pr-6 w-full lg:w-1/2" label="Postal code" />
</div>
<div class="px-8 py-4 bg-gray-50 border-t border-gray-100 flex justify-end items-center">
<div class="flex items-center justify-end px-8 py-4 bg-gray-50 border-t border-gray-100">
<loading-button :loading="form.processing" class="btn-indigo" type="submit">Create Contact</loading-button>
</div>
</form>

View File

@ -1,36 +1,34 @@
<template>
<div>
<Head :title="`${form.first_name} ${form.last_name}`" />
<h1 class="mb-8 font-bold text-3xl">
<h1 class="mb-8 text-3xl font-bold">
<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>
<trashed-message v-if="contact.deleted_at" class="mb-6" @restore="restore">
This contact has been deleted.
</trashed-message>
<div class="bg-white rounded-md shadow overflow-hidden max-w-3xl">
<trashed-message v-if="contact.deleted_at" class="mb-6" @restore="restore"> This contact has been deleted. </trashed-message>
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form @submit.prevent="update">
<div class="p-8 -mr-6 -mb-8 flex flex-wrap">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pr-6 pb-8 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pr-6 pb-8 w-full lg:w-1/2" label="Last name" />
<select-input v-model="form.organization_id" :error="form.errors.organization_id" class="pr-6 pb-8 w-full lg:w-1/2" label="Organization">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pb-8 pr-6 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pb-8 pr-6 w-full lg:w-1/2" label="Last name" />
<select-input v-model="form.organization_id" :error="form.errors.organization_id" class="pb-8 pr-6 w-full lg:w-1/2" label="Organization">
<option :value="null" />
<option v-for="organization in organizations" :key="organization.id" :value="organization.id">{{ organization.name }}</option>
</select-input>
<text-input v-model="form.email" :error="form.errors.email" class="pr-6 pb-8 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pr-6 pb-8 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pr-6 pb-8 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pr-6 pb-8 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pr-6 pb-8 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pr-6 pb-8 w-full lg:w-1/2" label="Country">
<text-input v-model="form.email" :error="form.errors.email" class="pb-8 pr-6 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pb-8 pr-6 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pb-8 pr-6 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pb-8 pr-6 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pb-8 pr-6 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pb-8 pr-6 w-full lg:w-1/2" label="Country">
<option :value="null" />
<option value="CA">Canada</option>
<option value="US">United States</option>
</select-input>
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pr-6 pb-8 w-full lg:w-1/2" label="Postal code" />
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pb-8 pr-6 w-full lg:w-1/2" label="Postal code" />
</div>
<div class="px-8 py-4 bg-gray-50 border-t border-gray-100 flex items-center">
<div class="flex items-center px-8 py-4 bg-gray-50 border-t border-gray-100">
<button v-if="!contact.deleted_at" class="text-red-600 hover:underline" tabindex="-1" type="button" @click="destroy">Delete Contact</button>
<loading-button :loading="form.processing" class="btn-indigo ml-auto" type="submit">Update Contact</loading-button>
</div>

View File

@ -1,11 +1,11 @@
<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">
<h1 class="mb-8 text-3xl font-bold">Contacts</h1>
<div class="flex items-center justify-between mb-6">
<search-filter v-model="form.search" class="mr-4 w-full max-w-md" @reset="reset">
<label class="block text-gray-700">Trashed:</label>
<select v-model="form.trashed" class="mt-1 w-full form-select">
<select v-model="form.trashed" class="form-select mt-1 w-full">
<option :value="null" />
<option value="with">With Trashed</option>
<option value="only">Only Trashed</option>
@ -19,43 +19,43 @@
<div class="bg-white rounded-md shadow overflow-x-auto">
<table class="w-full whitespace-nowrap">
<tr class="text-left font-bold">
<th class="px-6 pt-6 pb-4">Name</th>
<th class="px-6 pt-6 pb-4">Organization</th>
<th class="px-6 pt-6 pb-4">City</th>
<th class="px-6 pt-6 pb-4" colspan="2">Phone</th>
<th class="pb-4 pt-6 px-6">Name</th>
<th class="pb-4 pt-6 px-6">Organization</th>
<th class="pb-4 pt-6 px-6">City</th>
<th class="pb-4 pt-6 px-6" colspan="2">Phone</th>
</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">
<Link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="`/contacts/${contact.id}/edit`">
<Link class="flex items-center px-6 py-4 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" />
<icon v-if="contact.deleted_at" name="trash" class="flex-shrink-0 ml-2 w-3 h-3 fill-gray-400" />
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<div v-if="contact.organization">
{{ contact.organization.name }}
</div>
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
{{ contact.city }}
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
{{ contact.phone }}
</Link>
</td>
<td class="border-t w-px">
<Link class="px-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<td class="w-px border-t">
<Link class="flex items-center px-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" />
</Link>
</td>
</tr>
<tr v-if="contacts.data.length === 0">
<td class="border-t px-6 py-4" colspan="4">No contacts found.</td>
<td class="px-6 py-4 border-t" colspan="4">No contacts found.</td>
</tr>
</table>
</div>
@ -97,7 +97,7 @@ export default {
watch: {
form: {
deep: true,
handler: throttle(function() {
handler: throttle(function () {
this.$inertia.get('/contacts', pickBy(this.form), { preserveState: true })
}, 150),
},

View File

@ -1,8 +1,8 @@
<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>
<h1 class="mb-8 text-3xl font-bold">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 hover:text-orange-600 underline" href="https://inertiajs.com">Inertia.js</a> works.</p>
</div>
</template>

View File

@ -1,27 +1,27 @@
<template>
<div>
<Head title="Create Organization" />
<h1 class="mb-8 font-bold text-3xl">
<h1 class="mb-8 text-3xl font-bold">
<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">
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form @submit.prevent="store">
<div class="p-8 -mr-6 -mb-8 flex flex-wrap">
<text-input v-model="form.name" :error="form.errors.name" class="pr-6 pb-8 w-full lg:w-1/2" label="Name" />
<text-input v-model="form.email" :error="form.errors.email" class="pr-6 pb-8 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pr-6 pb-8 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pr-6 pb-8 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pr-6 pb-8 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pr-6 pb-8 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pr-6 pb-8 w-full lg:w-1/2" label="Country">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="form.name" :error="form.errors.name" class="pb-8 pr-6 w-full lg:w-1/2" label="Name" />
<text-input v-model="form.email" :error="form.errors.email" class="pb-8 pr-6 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pb-8 pr-6 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pb-8 pr-6 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pb-8 pr-6 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pb-8 pr-6 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pb-8 pr-6 w-full lg:w-1/2" label="Country">
<option :value="null" />
<option value="CA">Canada</option>
<option value="US">United States</option>
</select-input>
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pr-6 pb-8 w-full lg:w-1/2" label="Postal code" />
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pb-8 pr-6 w-full lg:w-1/2" label="Postal code" />
</div>
<div class="px-8 py-4 bg-gray-50 border-t border-gray-100 flex justify-end items-center">
<div class="flex items-center justify-end px-8 py-4 bg-gray-50 border-t border-gray-100">
<loading-button :loading="form.processing" class="btn-indigo" type="submit">Create Organization</loading-button>
</div>
</form>

View File

@ -1,69 +1,67 @@
<template>
<div>
<Head :title="form.name" />
<h1 class="mb-8 font-bold text-3xl">
<h1 class="mb-8 text-3xl font-bold">
<Link class="text-indigo-400 hover:text-indigo-600" href="/organizations">Organizations</Link>
<span class="text-indigo-400 font-medium">/</span>
{{ form.name }}
</h1>
<trashed-message v-if="organization.deleted_at" class="mb-6" @restore="restore">
This organization has been deleted.
</trashed-message>
<div class="bg-white rounded-md shadow overflow-hidden max-w-3xl">
<trashed-message v-if="organization.deleted_at" class="mb-6" @restore="restore"> This organization has been deleted. </trashed-message>
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form @submit.prevent="update">
<div class="p-8 -mr-6 -mb-8 flex flex-wrap">
<text-input v-model="form.name" :error="form.errors.name" class="pr-6 pb-8 w-full lg:w-1/2" label="Name" />
<text-input v-model="form.email" :error="form.errors.email" class="pr-6 pb-8 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pr-6 pb-8 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pr-6 pb-8 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pr-6 pb-8 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pr-6 pb-8 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pr-6 pb-8 w-full lg:w-1/2" label="Country">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="form.name" :error="form.errors.name" class="pb-8 pr-6 w-full lg:w-1/2" label="Name" />
<text-input v-model="form.email" :error="form.errors.email" class="pb-8 pr-6 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.phone" :error="form.errors.phone" class="pb-8 pr-6 w-full lg:w-1/2" label="Phone" />
<text-input v-model="form.address" :error="form.errors.address" class="pb-8 pr-6 w-full lg:w-1/2" label="Address" />
<text-input v-model="form.city" :error="form.errors.city" class="pb-8 pr-6 w-full lg:w-1/2" label="City" />
<text-input v-model="form.region" :error="form.errors.region" class="pb-8 pr-6 w-full lg:w-1/2" label="Province/State" />
<select-input v-model="form.country" :error="form.errors.country" class="pb-8 pr-6 w-full lg:w-1/2" label="Country">
<option :value="null" />
<option value="CA">Canada</option>
<option value="US">United States</option>
</select-input>
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pr-6 pb-8 w-full lg:w-1/2" label="Postal code" />
<text-input v-model="form.postal_code" :error="form.errors.postal_code" class="pb-8 pr-6 w-full lg:w-1/2" label="Postal code" />
</div>
<div class="px-8 py-4 bg-gray-50 border-t border-gray-100 flex items-center">
<div class="flex items-center px-8 py-4 bg-gray-50 border-t border-gray-100">
<button v-if="!organization.deleted_at" class="text-red-600 hover:underline" tabindex="-1" type="button" @click="destroy">Delete Organization</button>
<loading-button :loading="form.processing" class="btn-indigo ml-auto" type="submit">Update Organization</loading-button>
</div>
</form>
</div>
<h2 class="mt-12 font-bold text-2xl">Contacts</h2>
<h2 class="mt-12 text-2xl font-bold">Contacts</h2>
<div class="mt-6 bg-white rounded shadow overflow-x-auto">
<table class="w-full whitespace-nowrap">
<tr class="text-left font-bold">
<th class="px-6 pt-6 pb-4">Name</th>
<th class="px-6 pt-6 pb-4">City</th>
<th class="px-6 pt-6 pb-4" colspan="2">Phone</th>
<th class="pb-4 pt-6 px-6">Name</th>
<th class="pb-4 pt-6 px-6">City</th>
<th class="pb-4 pt-6 px-6" colspan="2">Phone</th>
</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">
<Link class="px-6 py-4 flex items-center focus:text-indigo-500" :href="`/contacts/${contact.id}/edit`">
<Link class="flex items-center px-6 py-4 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" />
<icon v-if="contact.deleted_at" name="trash" class="flex-shrink-0 ml-2 w-3 h-3 fill-gray-400" />
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
{{ contact.city }}
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
{{ contact.phone }}
</Link>
</td>
<td class="border-t w-px">
<Link class="px-4 flex items-center" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<td class="w-px border-t">
<Link class="flex items-center px-4" :href="`/contacts/${contact.id}/edit`" tabindex="-1">
<icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" />
</Link>
</td>
</tr>
<tr v-if="organization.contacts.length === 0">
<td class="border-t px-6 py-4" colspan="4">No contacts found.</td>
<td class="px-6 py-4 border-t" colspan="4">No contacts found.</td>
</tr>
</table>
</div>

View File

@ -1,11 +1,11 @@
<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">
<h1 class="mb-8 text-3xl font-bold">Organizations</h1>
<div class="flex items-center justify-between mb-6">
<search-filter v-model="form.search" class="mr-4 w-full max-w-md" @reset="reset">
<label class="block text-gray-700">Trashed:</label>
<select v-model="form.trashed" class="mt-1 w-full form-select">
<select v-model="form.trashed" class="form-select mt-1 w-full">
<option :value="null" />
<option value="with">With Trashed</option>
<option value="only">Only Trashed</option>
@ -18,37 +18,41 @@
</div>
<div class="bg-white rounded-md shadow overflow-x-auto">
<table class="w-full whitespace-nowrap">
<tr class="text-left font-bold">
<th class="px-6 pt-6 pb-4">Name</th>
<th class="px-6 pt-6 pb-4">City</th>
<th class="px-6 pt-6 pb-4" colspan="2">Phone</th>
</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">
<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" />
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/organizations/${organization.id}/edit`" tabindex="-1">
{{ organization.city }}
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/organizations/${organization.id}/edit`" tabindex="-1">
{{ organization.phone }}
</Link>
</td>
<td class="border-t w-px">
<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" />
</Link>
</td>
</tr>
<tr v-if="organizations.data.length === 0">
<td class="border-t px-6 py-4" colspan="4">No organizations found.</td>
</tr>
<thead>
<tr class="text-left font-bold">
<th class="pb-4 pt-6 px-6">Name</th>
<th class="pb-4 pt-6 px-6">City</th>
<th class="pb-4 pt-6 px-6" colspan="2">Phone</th>
</tr>
</thead>
<tbody>
<tr v-for="organization in organizations.data" :key="organization.id" class="hover:bg-gray-100 focus-within:bg-gray-100">
<td class="border-t">
<Link class="flex items-center px-6 py-4 focus:text-indigo-500" :href="`/organizations/${organization.id}/edit`">
{{ organization.name }}
<icon v-if="organization.deleted_at" name="trash" class="flex-shrink-0 ml-2 w-3 h-3 fill-gray-400" />
</Link>
</td>
<td class="border-t">
<Link class="flex items-center px-6 py-4" :href="`/organizations/${organization.id}/edit`" tabindex="-1">
{{ organization.city }}
</Link>
</td>
<td class="border-t">
<Link class="flex items-center px-6 py-4" :href="`/organizations/${organization.id}/edit`" tabindex="-1">
{{ organization.phone }}
</Link>
</td>
<td class="w-px border-t">
<Link class="flex items-center px-4" :href="`/organizations/${organization.id}/edit`" tabindex="-1">
<icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" />
</Link>
</td>
</tr>
<tr v-if="organizations.data.length === 0">
<td class="px-6 py-4 border-t" colspan="4">No organizations found.</td>
</tr>
</tbody>
</table>
</div>
<pagination class="mt-6" :links="organizations.links" />
@ -89,7 +93,7 @@ export default {
watch: {
form: {
deep: true,
handler: throttle(function() {
handler: throttle(function () {
this.$inertia.get('/organizations', pickBy(this.form), { preserveState: true })
}, 150),
},

View File

@ -1,7 +1,7 @@
<template>
<div>
<Head title="Reports" />
<h1 class="mb-8 font-bold text-3xl">Reports</h1>
<h1 class="mb-8 text-3xl font-bold">Reports</h1>
</div>
</template>

View File

@ -1,24 +1,24 @@
<template>
<div>
<Head title="Create User" />
<h1 class="mb-8 font-bold text-3xl">
<h1 class="mb-8 text-3xl font-bold">
<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">
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form @submit.prevent="store">
<div class="p-8 -mr-6 -mb-8 flex flex-wrap">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pr-6 pb-8 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pr-6 pb-8 w-full lg:w-1/2" label="Last name" />
<text-input v-model="form.email" :error="form.errors.email" class="pr-6 pb-8 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.password" :error="form.errors.password" class="pr-6 pb-8 w-full lg:w-1/2" type="password" autocomplete="new-password" label="Password" />
<select-input v-model="form.owner" :error="form.errors.owner" class="pr-6 pb-8 w-full lg:w-1/2" label="Owner">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pb-8 pr-6 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pb-8 pr-6 w-full lg:w-1/2" label="Last name" />
<text-input v-model="form.email" :error="form.errors.email" class="pb-8 pr-6 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.password" :error="form.errors.password" class="pb-8 pr-6 w-full lg:w-1/2" type="password" autocomplete="new-password" label="Password" />
<select-input v-model="form.owner" :error="form.errors.owner" class="pb-8 pr-6 w-full lg:w-1/2" label="Owner">
<option :value="true">Yes</option>
<option :value="false">No</option>
</select-input>
<file-input v-model="form.photo" :error="form.errors.photo" class="pr-6 pb-8 w-full lg:w-1/2" type="file" accept="image/*" label="Photo" />
<file-input v-model="form.photo" :error="form.errors.photo" class="pb-8 pr-6 w-full lg:w-1/2" type="file" accept="image/*" label="Photo" />
</div>
<div class="px-8 py-4 bg-gray-50 border-t border-gray-100 flex justify-end items-center">
<div class="flex items-center justify-end px-8 py-4 bg-gray-50 border-t border-gray-100">
<loading-button :loading="form.processing" class="btn-indigo" type="submit">Create User</loading-button>
</div>
</form>

View File

@ -1,31 +1,29 @@
<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">
<div class="flex justify-start mb-8 max-w-3xl">
<h1 class="text-3xl font-bold">
<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>
<img v-if="user.photo" class="block w-8 h-8 rounded-full ml-4" :src="user.photo" />
<img v-if="user.photo" class="block ml-4 w-8 h-8 rounded-full" :src="user.photo" />
</div>
<trashed-message v-if="user.deleted_at" class="mb-6" @restore="restore">
This user has been deleted.
</trashed-message>
<div class="bg-white rounded-md shadow overflow-hidden max-w-3xl">
<trashed-message v-if="user.deleted_at" class="mb-6" @restore="restore"> This user has been deleted. </trashed-message>
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form @submit.prevent="update">
<div class="p-8 -mr-6 -mb-8 flex flex-wrap">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pr-6 pb-8 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pr-6 pb-8 w-full lg:w-1/2" label="Last name" />
<text-input v-model="form.email" :error="form.errors.email" class="pr-6 pb-8 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.password" :error="form.errors.password" class="pr-6 pb-8 w-full lg:w-1/2" type="password" autocomplete="new-password" label="Password" />
<select-input v-model="form.owner" :error="form.errors.owner" class="pr-6 pb-8 w-full lg:w-1/2" label="Owner">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="form.first_name" :error="form.errors.first_name" class="pb-8 pr-6 w-full lg:w-1/2" label="First name" />
<text-input v-model="form.last_name" :error="form.errors.last_name" class="pb-8 pr-6 w-full lg:w-1/2" label="Last name" />
<text-input v-model="form.email" :error="form.errors.email" class="pb-8 pr-6 w-full lg:w-1/2" label="Email" />
<text-input v-model="form.password" :error="form.errors.password" class="pb-8 pr-6 w-full lg:w-1/2" type="password" autocomplete="new-password" label="Password" />
<select-input v-model="form.owner" :error="form.errors.owner" class="pb-8 pr-6 w-full lg:w-1/2" label="Owner">
<option :value="true">Yes</option>
<option :value="false">No</option>
</select-input>
<file-input v-model="form.photo" :error="form.errors.photo" class="pr-6 pb-8 w-full lg:w-1/2" type="file" accept="image/*" label="Photo" />
<file-input v-model="form.photo" :error="form.errors.photo" class="pb-8 pr-6 w-full lg:w-1/2" type="file" accept="image/*" label="Photo" />
</div>
<div class="px-8 py-4 bg-gray-50 border-t border-gray-100 flex items-center">
<div class="flex items-center px-8 py-4 bg-gray-50 border-t border-gray-100">
<button v-if="!user.deleted_at" class="text-red-600 hover:underline" tabindex="-1" type="button" @click="destroy">Delete User</button>
<loading-button :loading="form.processing" class="btn-indigo ml-auto" type="submit">Update User</loading-button>
</div>

View File

@ -1,17 +1,17 @@
<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">
<h1 class="mb-8 text-3xl font-bold">Users</h1>
<div class="flex items-center justify-between mb-6">
<search-filter v-model="form.search" class="mr-4 w-full max-w-md" @reset="reset">
<label class="block text-gray-700">Role:</label>
<select v-model="form.role" class="mt-1 w-full form-select">
<select v-model="form.role" class="form-select mt-1 w-full">
<option :value="null" />
<option value="user">User</option>
<option value="owner">Owner</option>
</select>
<label class="mt-4 block text-gray-700">Trashed:</label>
<select v-model="form.trashed" class="mt-1 w-full form-select">
<label class="block mt-4 text-gray-700">Trashed:</label>
<select v-model="form.trashed" class="form-select mt-1 w-full">
<option :value="null" />
<option value="with">With Trashed</option>
<option value="only">Only Trashed</option>
@ -25,36 +25,36 @@
<div class="bg-white rounded-md shadow overflow-x-auto">
<table class="w-full whitespace-nowrap">
<tr class="text-left font-bold">
<th class="px-6 pt-6 pb-4">Name</th>
<th class="px-6 pt-6 pb-4">Email</th>
<th class="px-6 pt-6 pb-4" colspan="2">Role</th>
<th class="pb-4 pt-6 px-6">Name</th>
<th class="pb-4 pt-6 px-6">Email</th>
<th class="pb-4 pt-6 px-6" colspan="2">Role</th>
</tr>
<tr v-for="user in users" :key="user.id" class="hover:bg-gray-100 focus-within:bg-gray-100">
<td class="border-t">
<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" />
<Link class="flex items-center px-6 py-4 focus:text-indigo-500" :href="`/users/${user.id}/edit`">
<img v-if="user.photo" class="block -my-2 mr-2 w-5 h-5 rounded-full" :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" />
<icon v-if="user.deleted_at" name="trash" class="flex-shrink-0 ml-2 w-3 h-3 fill-gray-400" />
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/users/${user.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/users/${user.id}/edit`" tabindex="-1">
{{ user.email }}
</Link>
</td>
<td class="border-t">
<Link class="px-6 py-4 flex items-center" :href="`/users/${user.id}/edit`" tabindex="-1">
<Link class="flex items-center px-6 py-4" :href="`/users/${user.id}/edit`" tabindex="-1">
{{ user.owner ? 'Owner' : 'User' }}
</Link>
</td>
<td class="border-t w-px">
<Link class="px-4 flex items-center" :href="`/users/${user.id}/edit`" tabindex="-1">
<td class="w-px border-t">
<Link class="flex items-center px-4" :href="`/users/${user.id}/edit`" tabindex="-1">
<icon name="cheveron-right" class="block w-6 h-6 fill-gray-400" />
</Link>
</td>
</tr>
<tr v-if="users.length === 0">
<td class="border-t px-6 py-4" colspan="4">No users found.</td>
<td class="px-6 py-4 border-t" colspan="4">No users found.</td>
</tr>
</table>
</div>
@ -94,7 +94,7 @@ export default {
watch: {
form: {
deep: true,
handler: throttle(function() {
handler: throttle(function () {
this.$inertia.get('/users', pickBy(this.form), { preserveState: true })
}, 150),
},

View File

@ -3,8 +3,8 @@
<slot />
<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">
<div style="position: fixed; top: 0; right: 0; left: 0; bottom: 0; z-index: 99998; background: black; opacity: 0.2" @click="show = false" />
<div ref="dropdown" style="position: absolute; z-index: 99999" @click.stop="show = !autoClose">
<slot name="dropdown" />
</div>
</div>
@ -53,7 +53,7 @@ export default {
},
},
mounted() {
document.addEventListener('keydown', e => {
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.show = false
}

View File

@ -4,17 +4,13 @@
<div class="form-input p-0" :class="{ error: errors.length }">
<input ref="file" type="file" :accept="accept" class="hidden" @change="change" />
<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>
<button type="button" class="px-4 py-1 text-white text-xs font-medium bg-gray-500 hover:bg-gray-700 rounded-sm" @click="browse">Browse</button>
</div>
<div v-else class="flex items-center justify-between p-2">
<div class="flex-1 pr-1">
{{ 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
</button>
<button type="button" class="px-4 py-1 text-white text-xs font-medium bg-gray-500 hover:bg-gray-700 rounded-sm" @click="remove">Remove</button>
</div>
</div>
<div v-if="errors.length" class="form-error">{{ errors[0] }}</div>
@ -32,6 +28,7 @@ export default {
default: () => [],
},
},
emits: ['update:modelValue'],
watch: {
modelValue(value) {
if (!value) {

View File

@ -1,17 +1,17 @@
<template>
<div>
<div v-if="$page.props.flash.success && show" class="mb-8 flex items-center justify-between bg-green-500 rounded max-w-3xl">
<div v-if="$page.props.flash.success && show" class="flex items-center justify-between mb-8 max-w-3xl bg-green-500 rounded">
<div class="flex items-center">
<svg class="ml-4 mr-2 flex-shrink-0 w-4 h-4 fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="0 11 2 9 7 14 18 3 20 5 7 18" /></svg>
<svg class="flex-shrink-0 ml-4 mr-2 w-4 h-4 fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="0 11 2 9 7 14 18 3 20 5 7 18" /></svg>
<div class="py-4 text-white text-sm font-medium">{{ $page.props.flash.success }}</div>
</div>
<button type="button" class="group mr-2 p-2" @click="show = false">
<svg class="block w-2 h-2 fill-green-800 group-hover:fill-white" xmlns="http://www.w3.org/2000/svg" width="235.908" height="235.908" viewBox="278.046 126.846 235.908 235.908"><path d="M506.784 134.017c-9.56-9.56-25.06-9.56-34.62 0L396 210.18l-76.164-76.164c-9.56-9.56-25.06-9.56-34.62 0-9.56 9.56-9.56 25.06 0 34.62L361.38 244.8l-76.164 76.165c-9.56 9.56-9.56 25.06 0 34.62 9.56 9.56 25.06 9.56 34.62 0L396 279.42l76.164 76.165c9.56 9.56 25.06 9.56 34.62 0 9.56-9.56 9.56-25.06 0-34.62L430.62 244.8l76.164-76.163c9.56-9.56 9.56-25.06 0-34.62z" /></svg>
</button>
</div>
<div v-if="($page.props.flash.error || Object.keys($page.props.errors).length > 0) && show" class="mb-8 flex items-center justify-between bg-red-400 rounded max-w-3xl">
<div v-if="($page.props.flash.error || Object.keys($page.props.errors).length > 0) && show" class="flex items-center justify-between mb-8 max-w-3xl bg-red-500 rounded">
<div class="flex items-center">
<svg class="ml-4 mr-2 flex-shrink-0 w-4 h-4 fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm1.41-1.41A8 8 0 1 0 15.66 4.34 8 8 0 0 0 4.34 15.66zm9.9-8.49L11.41 10l2.83 2.83-1.41 1.41L10 11.41l-2.83 2.83-1.41-1.41L8.59 10 5.76 7.17l1.41-1.41L10 8.59l2.83-2.83 1.41 1.41z" /></svg>
<svg class="flex-shrink-0 ml-4 mr-2 w-4 h-4 fill-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm1.41-1.41A8 8 0 1 0 15.66 4.34 8 8 0 0 0 4.34 15.66zm9.9-8.49L11.41 10l2.83 2.83-1.41 1.41L10 11.41l-2.83 2.83-1.41-1.41L8.59 10 5.76 7.17l1.41-1.41L10 8.59l2.83-2.83 1.41 1.41z" /></svg>
<div v-if="$page.props.flash.error" class="py-4 text-white text-sm font-medium">{{ $page.props.flash.error }}</div>
<div v-else class="py-4 text-white text-sm font-medium">
<span v-if="Object.keys($page.props.errors).length === 1">There is one form error.</span>

View File

@ -1,14 +1,9 @@
<template>
<svg v-if="name === 'apple'" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><g fill-rule="nonzero"><path d="M46.173 19.967C49.927-1.838 19.797-.233 14.538.21c-.429.035-.648.4-.483.8 2.004 4.825 14.168 31.66 32.118 18.957zm13.18 1.636c1.269-.891 1.35-1.614.047-2.453l-2.657-1.71c-.94-.607-1.685-.606-2.532.129-5.094 4.42-7.336 9.18-8.211 15.24 1.597.682 3.55.79 5.265.328 1.298-4.283 3.64-8.412 8.088-11.534z" /><path d="M88.588 67.75c9.65-27.532-13.697-45.537-35.453-32.322-1.84 1.118-4.601 1.118-6.441 0-21.757-13.215-45.105 4.79-35.454 32.321 5.302 15.123 17.06 39.95 37.295 29.995.772-.38 1.986-.38 2.758 0 20.235 9.955 31.991-14.872 37.295-29.995z" /></g></svg>
<svg v-else-if="name === 'book'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M6 4H5a1 1 0 1 1 0-2h11V1a1 1 0 0 0-1-1H4a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V5a1 1 0 0 0-1-1h-7v8l-2-2-2 2V4z" /></svg>
<svg v-else-if="name === 'cheveron-down'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /></svg>
<svg v-if="name === 'cheveron-down'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /></svg>
<svg v-else-if="name === 'cheveron-right'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="12.95 10.707 13.657 10 8 4.343 6.586 5.757 10.828 10 6.586 14.243 8 15.657 12.95 10.707" /></svg>
<svg v-else-if="name === 'dashboard'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm-5.6-4.29a9.95 9.95 0 0 1 11.2 0 8 8 0 1 0-11.2 0zm6.12-7.64l3.02-3.02 1.41 1.41-3.02 3.02a2 2 0 1 1-1.41-1.41z" /></svg>
<svg v-else-if="name === 'location'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 20S3 10.87 3 7a7 7 0 1 1 14 0c0 3.87-7 13-7 13zm0-11a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" /></svg>
<svg v-else-if="name === 'office'" xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path fill-rule="evenodd" d="M7 0h86v100H57.108V88.418H42.892V100H7V0zm9 64h11v15H16V64zm57 0h11v15H73V64zm-19 0h11v15H54V64zm-19 0h11v15H35V64zM16 37h11v15H16V37zm57 0h11v15H73V37zm-19 0h11v15H54V37zm-19 0h11v15H35V37zM16 11h11v15H16V11zm57 0h11v15H73V11zm-19 0h11v15H54V11zm-19 0h11v15H35V11z" /></svg>
<svg v-else-if="name === 'printer'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M4 16H0V6h20v10h-4v4H4v-4zm2-4v6h8v-6H6zM4 0h12v5H4V0zM2 8v2h2V8H2zm4 0v2h2V8H6z" /></svg>
<svg v-else-if="name === 'shopping-cart'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M4 2h16l-3 9H4a1 1 0 1 0 0 2h13v2H4a3 3 0 0 1 0-6h.33L3 5 2 2H0V0h3a1 1 0 0 1 1 1v1zm1 18a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm10 0a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" /></svg>
<svg v-else-if="name === 'store-front'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M18 9.87V20H2V9.87a4.25 4.25 0 0 0 3-.38V14h10V9.5a4.26 4.26 0 0 0 3 .37zM3 0h4l-.67 6.03A3.43 3.43 0 0 1 3 9C1.34 9 .42 7.73.95 6.15L3 0zm5 0h4l.7 6.3c.17 1.5-.91 2.7-2.42 2.7h-.56A2.38 2.38 0 0 1 7.3 6.3L8 0zm5 0h4l2.05 6.15C19.58 7.73 18.65 9 17 9a3.42 3.42 0 0 1-3.33-2.97L13 0z" /></svg>
<svg v-else-if="name === 'trash'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M6 2l2-2h4l2 2h4v2H2V2h4zM3 6h14l-1 14H4L3 6zm5 2v10h1V8H8zm3 0v10h1V8h-1z" /></svg>
<svg v-else-if="name === 'users'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M7 8a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0 1c2.15 0 4.2.4 6.1 1.09L12 16h-1.25L10 20H4l-.75-4H2L.9 10.09A17.93 17.93 0 0 1 7 9zm8.31.17c1.32.18 2.59.48 3.8.92L18 16h-1.25L16 20h-3.96l.37-2h1.25l1.65-8.83zM13 0a4 4 0 1 1-1.33 7.76 5.96 5.96 0 0 0 0-7.52C12.1.1 12.53 0 13 0z" /></svg>
</template>

View File

@ -2,48 +2,48 @@
<div>
<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-col md:h-screen">
<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">
<div class="flex items-center justify-between px-6 py-4 bg-indigo-900 md:flex-shrink-0 md:justify-center md:w-56">
<Link class="mt-1" href="/">
<logo class="fill-white" width="120" height="28" />
</Link>
<dropdown class="md:hidden" placement="bottom-end">
<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>
<svg class="w-6 h-6 fill-white" 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">
<div class="mt-2 px-8 py-4 bg-indigo-800 rounded shadow-lg">
<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">{{ auth.user.account.name }}</div>
<div class="md:text-md flex items-center justify-between p-4 w-full text-sm bg-white border-b md:px-12 md:py-0">
<div class="mr-4 mt-1">{{ auth.user.account.name }}</div>
<dropdown class="mt-1" placement="bottom-end">
<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">
<div class="group flex items-center cursor-pointer select-none">
<div class="mr-1 text-gray-700 group-hover:text-indigo-600 focus:text-indigo-600 whitespace-nowrap">
<span>{{ auth.user.first_name }}</span>
<span class="hidden md:inline">&nbsp;{{ 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" />
<icon class="w-5 h-5 fill-gray-700 group-hover:fill-indigo-600 focus:fill-indigo-600" name="cheveron-down" />
</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 class="mt-2 py-2 text-sm bg-white rounded shadow-xl">
<Link class="block px-6 py-2 hover:text-white hover:bg-indigo-500" :href="`/users/${auth.user.id}/edit`">My Profile</Link>
<Link class="block px-6 py-2 hover:text-white hover:bg-indigo-500" href="/users">Manage Users</Link>
<Link class="block px-6 py-2 w-full text-left hover:text-white hover:bg-indigo-500" href="/logout" method="delete" as="button">Logout</Link>
</div>
</template>
</dropdown>
</div>
</div>
<div class="md:flex md:flex-grow md:overflow-hidden">
<main-menu class="hidden md:block bg-indigo-800 flex-shrink-0 w-56 p-12 overflow-y-auto" />
<div class="md:flex-1 px-4 py-8 md:p-12 md:overflow-y-auto" scroll-region>
<main-menu class="hidden flex-shrink-0 p-12 w-56 bg-indigo-800 overflow-y-auto md:block" />
<div class="px-4 py-8 md:flex-1 md:p-12 md:overflow-y-auto" scroll-region>
<flash-messages />
<slot />
</div>

View File

@ -1,26 +1,26 @@
<template>
<div>
<div class="mb-4">
<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'" />
<Link class="group flex items-center py-3" href="/">
<icon name="dashboard" class="mr-2 w-4 h-4" :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>
</Link>
</div>
<div class="mb-4">
<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'" />
<Link class="group flex items-center py-3" href="/organizations">
<icon name="office" class="mr-2 w-4 h-4" :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>
</Link>
</div>
<div class="mb-4">
<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'" />
<Link class="group flex items-center py-3" href="/contacts">
<icon name="users" class="mr-2 w-4 h-4" :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>
</Link>
</div>
<div class="mb-4">
<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'" />
<Link class="group flex items-center py-3" href="/reports">
<icon name="printer" class="mr-2 w-4 h-4" :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>
</Link>
</div>
@ -42,7 +42,7 @@ export default {
if (urls[0] === '') {
return currentUrl === ''
}
return urls.filter(url => currentUrl.startsWith(url)).length
return urls.filter((url) => currentUrl.startsWith(url)).length
},
},
}

View File

@ -2,8 +2,8 @@
<div v-if="links.length > 3">
<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" />
<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" />
<div v-if="link.url === null" :key="key" class="mb-1 mr-1 px-4 py-3 text-gray-400 text-sm leading-4 border rounded" v-html="link.label" />
<Link v-else :key="`link-${key}`" class="mb-1 mr-1 px-4 py-3 focus:text-indigo-500 text-sm leading-4 hover:bg-white border focus:border-indigo-500 rounded" :class="{ 'bg-white': link.active }" :href="link.url" v-html="link.label" />
</template>
</div>
</div>

View File

@ -1,24 +1,24 @@
<template>
<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 w-full bg-white rounded shadow">
<dropdown :auto-close="false" class="focus:z-10 px-4 hover:bg-gray-100 border-r focus:border-white rounded-l focus:ring md:px-6" placement="bottom-start">
<template #default>
<div class="flex items-baseline">
<span class="text-gray-700 hidden md:inline">Filter</span>
<span class="hidden text-gray-700 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` }">
<div class="mt-2 px-4 py-6 w-screen bg-white rounded shadow-xl" :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="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
<input class="relative px-6 py-3 w-full rounded-r focus:shadow-outline" 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>
<button class="ml-3 text-gray-500 hover:text-gray-700 focus:text-indigo-500 text-sm" type="button" @click="$emit('reset')">Reset</button>
</div>
</template>
@ -36,5 +36,6 @@ export default {
default: 300,
},
},
emits: ['update:modelValue', 'reset'],
}
</script>

View File

@ -25,6 +25,7 @@ export default {
label: String,
modelValue: [String, Number, Boolean],
},
emits: ['update:modelValue'],
data() {
return {
selected: this.modelValue,

View File

@ -27,6 +27,7 @@ export default {
label: String,
modelValue: String,
},
emits: ['update:modelValue'],
methods: {
focus() {
this.$refs.input.focus()

View File

@ -23,6 +23,7 @@ export default {
label: String,
modelValue: String,
},
emits: ['update:modelValue'],
methods: {
focus() {
this.$refs.input.focus()

View File

@ -1,12 +1,12 @@
<template>
<div class="p-4 bg-yellow-300 rounded flex items-center justify-between max-w-3xl">
<div class="flex items-center justify-between p-4 max-w-3xl bg-yellow-400 rounded">
<div class="flex items-center">
<icon name="trash" class="flex-shrink-0 w-4 h-4 fill-yellow-800 mr-2" />
<div class="text-sm font-medium text-yellow-800">
<icon name="trash" class="flex-shrink-0 mr-2 w-4 h-4 fill-yellow-800" />
<div class="text-yellow-800 text-sm font-medium">
<slot />
</div>
</div>
<button class="text-sm text-yellow-800 hover:underline" tabindex="-1" type="button" @click="$emit('restore')">Restore</button>
<button class="text-yellow-800 hover:underline text-sm" tabindex="-1" type="button" @click="$emit('restore')">Restore</button>
</div>
</template>
@ -17,5 +17,6 @@ export default {
components: {
Icon,
},
emits: ['restore'],
}
</script>

View File

@ -2957,6 +2957,14 @@ find-up@^4.0.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz"
@ -3842,6 +3850,13 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
dependencies:
p-locate "^5.0.0"
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
@ -4313,6 +4328,13 @@ p-limit@^2.2.0:
dependencies:
p-try "^2.0.0"
p-limit@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
yocto-queue "^0.1.0"
p-locate@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
@ -4320,6 +4342,13 @@ p-locate@^4.1.0:
dependencies:
p-limit "^2.2.0"
p-locate@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
dependencies:
p-limit "^3.0.2"
p-map@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz"
@ -4810,6 +4839,18 @@ prelude-ls@^1.2.1:
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier-plugin-tailwind@^2.2.12:
version "2.2.12"
resolved "https://registry.yarnpkg.com/prettier-plugin-tailwind/-/prettier-plugin-tailwind-2.2.12.tgz#959b4710f9245eb37765a922d3117c2df8c556f3"
integrity sha512-2SvZxpsYme0g5MrxGsKM43rx28f9AVlJrbwMnx4a03svCfsHwVGtcN6oN1YlClnEwZbquu3IhVAMcawEMKTjuA==
dependencies:
tailwind-classes-sorter "^0.2.5"
prettier@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
pretty-hrtime@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz"
@ -5541,6 +5582,13 @@ svgo@^2.7.0:
picocolors "^1.0.0"
stable "^0.1.8"
tailwind-classes-sorter@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/tailwind-classes-sorter/-/tailwind-classes-sorter-0.2.5.tgz#fa499fb5564783e5edd77259ce1a3ba9e0c8b3ad"
integrity sha512-7S0AaDitt+Fjy9m3v0GrQ/KZrCswNDD25SSXX9U/HIB5h9lk0ImSkq/VVcnzu78cRQxR0fFfvHYFdfcqN3dCGA==
dependencies:
find-up "^5.0.0"
tailwindcss@^2.0.3:
version "2.2.19"
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.19.tgz"
@ -6058,3 +6106,8 @@ yargs@^17.2.1:
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.0.0"
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==