Pārlūkot izejas kodu

Added send from alias address creator

Will Browning 4 gadi atpakaļ
vecāks
revīzija
f782a399dc

+ 2 - 2
.prettierrc

@@ -2,6 +2,6 @@
   "printWidth": 100,
   "printWidth": 100,
   "singleQuote": true,
   "singleQuote": true,
   "tabWidth": 2,
   "tabWidth": 2,
-  "trailingComma": "es5",
-  "semi": false
+  "semi": false,
+  "arrowParens": "avoid"
 }
 }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 188 - 167
composer.lock


+ 2 - 2
config/version.yml

@@ -5,9 +5,9 @@ current:
   major: 0
   major: 0
   minor: 6
   minor: 6
   patch: 1
   patch: 1
-  prerelease: ''
+  prerelease: 1-g47f7ada
   buildmetadata: ''
   buildmetadata: ''
-  commit: f1d596
+  commit: 47f7ad
   timestamp:
   timestamp:
     year: 2020
     year: 2020
     month: 10
     month: 10

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 280 - 283
package-lock.json


+ 12 - 14
package.json

@@ -11,17 +11,17 @@
         "format": "prettier --write 'resources/**/*.{css,js,vue}'"
         "format": "prettier --write 'resources/**/*.{css,js,vue}'"
     },
     },
     "dependencies": {
     "dependencies": {
-        "axios": "^0.19",
-        "cross-env": "^7.0",
-        "dayjs": "^1.9.6",
+        "autoprefixer": "^9.8.6",
+        "axios": "^0.21.0",
+        "cross-env": "^7.0.3",
+        "dayjs": "^1.9.7",
         "laravel-mix": "^5.0.9",
         "laravel-mix": "^5.0.9",
         "lodash": "^4.17.20",
         "lodash": "^4.17.20",
         "portal-vue": "^2.1.7",
         "portal-vue": "^2.1.7",
-        "postcss-import": "^11.1.0",
-        "postcss-nesting": "^5.0.0",
+        "postcss": "^7.0.35",
         "resolve-url-loader": "^3.1.2",
         "resolve-url-loader": "^3.1.2",
-        "tailwindcss": "^1.9.5",
-        "tippy.js": "^4.3.5",
+        "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",
+        "tippy.js": "^6.2.7",
         "v-clipboard": "^2.2.3",
         "v-clipboard": "^2.2.3",
         "vue": "^2.6.12",
         "vue": "^2.6.12",
         "vue-good-table": "^2.21.1",
         "vue-good-table": "^2.21.1",
@@ -31,9 +31,9 @@
         "vuedraggable": "^2.24.2"
         "vuedraggable": "^2.24.2"
     },
     },
     "devDependencies": {
     "devDependencies": {
-        "husky": "^2.7.0",
-        "lint-staged": "^8.2.1",
-        "prettier": "1.16.4"
+        "husky": "^4.3.6",
+        "lint-staged": "^10.5.3",
+        "prettier": "2.2.1"
     },
     },
     "husky": {
     "husky": {
         "hooks": {
         "hooks": {
@@ -42,12 +42,10 @@
     },
     },
     "lint-staged": {
     "lint-staged": {
         "*.{css,js,vue}": [
         "*.{css,js,vue}": [
-            "npm run format --",
-            "git add"
+            "npm run format --"
         ],
         ],
         "*.php": [
         "*.php": [
-            "composer format",
-            "git add"
+            "composer format"
         ]
         ]
     }
     }
 }
 }

+ 1 - 1
resources/css/app.css

@@ -256,7 +256,7 @@ table.vgt-table tr.clickable:hover {
 }
 }
 
 
 .vgt-wrap__footer .footer__navigation__page-btn {
 .vgt-wrap__footer .footer__navigation__page-btn {
-  @apply no-underline text-grey-500 font-bold whitespace-no-wrap;
+  @apply no-underline text-grey-500 font-bold whitespace-nowrap;
 }
 }
 
 
 .vgt-wrap__footer .footer__navigation__page-btn:focus {
 .vgt-wrap__footer .footer__navigation__page-btn:focus {

+ 15 - 0
resources/js/components/Icon.vue

@@ -264,6 +264,21 @@
     <line x1="3" y1="6" x2="21" y2="6"></line>
     <line x1="3" y1="6" x2="21" y2="6"></line>
     <line x1="3" y1="18" x2="21" y2="18"></line>
     <line x1="3" y1="18" x2="21" y2="18"></line>
   </svg>
   </svg>
+  <svg
+    v-else-if="name === 'more'"
+    xmlns="http://www.w3.org/2000/svg"
+    viewBox="0 0 24 24"
+    fill="none"
+    stroke="currentColor"
+    stroke-width="2"
+    stroke-linecap="round"
+    stroke-linejoin="round"
+    aria-hidden="true"
+  >
+    <circle cx="12" cy="12" r="1"></circle>
+    <circle cx="12" cy="5" r="1"></circle>
+    <circle cx="12" cy="19" r="1"></circle>
+  </svg>
 </template>
 </template>
 
 
 <script>
 <script>

+ 1 - 1
resources/js/components/Loader.vue

@@ -8,7 +8,7 @@
       x="0px"
       x="0px"
       y="0px"
       y="0px"
       viewBox="0 0 50 50"
       viewBox="0 0 50 50"
-      style="enable-background:new 0 0 50 50;"
+      style="enable-background: new 0 0 50 50"
       xml:space="preserve"
       xml:space="preserve"
     >
     >
       <path
       <path

+ 1 - 1
resources/js/components/Modal.vue

@@ -79,7 +79,7 @@ export default {
   },
   },
   watch: {
   watch: {
     open: {
     open: {
-      handler: function(newValue) {
+      handler: function (newValue) {
         if (newValue) {
         if (newValue) {
           this.show()
           this.show()
         } else {
         } else {

+ 65 - 0
resources/js/components/MoreOptions.vue

@@ -0,0 +1,65 @@
+<template>
+  <div class="relative flex justify-end items-center" @keydown.escape="isOpen = false">
+    <button
+      ref="openOptions"
+      @click="isOpen = !isOpen"
+      :aria-expanded="isOpen"
+      id="project-options-menu-0"
+      aria-has-popup="true"
+      type="button"
+      class="w-8 h-8 bg-white inline-flex items-center justify-center text-grey-400 rounded-full hover:text-grey-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"
+    >
+      <span class="sr-only">Open options</span>
+
+      <icon
+        name="more"
+        class="block w-6 h-6 text-grey-300 fill-current cursor-pointer outline-none"
+        aria-hidden="true"
+      />
+    </button>
+
+    <transition
+      enter-active-class="transition ease-out duration-100"
+      enter-class="transform opacity-0 scale-95"
+      enter-to-class="transform opacity-100 scale-100"
+      leave-active-class="transition ease-in duration-75"
+      leave-class="transform opacity-100 scale-100"
+      leave-to-class="transform opacity-0 scale-95"
+    >
+      <div
+        v-show="isOpen"
+        class="mx-3 origin-top-right absolute right-7 top-0 w-48 mt-1 rounded-md shadow-lg z-10 bg-white ring-1 ring-black ring-opacity-5 divide-y divide-grey-200"
+        role="menu"
+        aria-orientation="vertical"
+        aria-labelledby="project-options-menu-0"
+      >
+        <slot></slot>
+      </div>
+    </transition>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      isOpen: false,
+    }
+  },
+  created() {
+    window.addEventListener('click', this.close)
+  },
+
+  beforeDestroy() {
+    window.removeEventListener('click', this.close)
+  },
+
+  methods: {
+    close(e) {
+      if (!this.$refs.openOptions.contains(e.target)) {
+        this.isOpen = false
+      }
+    },
+  },
+}
+</script>

+ 37 - 31
resources/js/components/Toggle.vue

@@ -1,21 +1,44 @@
 <template>
 <template>
-  <span
-    class="relative outline-none cursor-pointer h-6 w-12 rounded-full"
+  <button
     @click="toggle"
     @click="toggle"
-    role="checkbox"
-    :aria-checked="value.toString()"
-    tabindex="0"
-    @keydown.space.prevent="toggle"
+    type="button"
+    :aria-pressed="value.toString()"
+    :class="this.value ? 'bg-cyan-500' : 'bg-grey-300'"
+    class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none"
   >
   >
+    <span class="sr-only">Use setting</span>
     <span
     <span
-      class="toggle-background inline-block rounded-full h-full w-full shadow-inner"
-      :class="this.value ? 'bg-cyan-500' : 'bg-grey-300'"
-    ></span>
-    <span
-      class="toggle-indicator absolute bg-white rounded-full shadow w-4 h-4"
-      :style="indicatorStyles"
-    ></span>
-  </span>
+      :class="this.value ? 'translate-x-5' : 'translate-x-0'"
+      class="relative inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"
+    >
+      <span
+        :class="this.value ? 'opacity-0 ease-out duration-100' : 'opacity-100 ease-in duration-200'"
+        class="absolute inset-0 h-full w-full flex items-center justify-center transition-opacity"
+        aria-hidden="true"
+      >
+        <svg class="h-3 w-3 text-grey-400" fill="none" viewBox="0 0 12 12">
+          <path
+            d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2"
+            stroke="currentColor"
+            stroke-width="2"
+            stroke-linecap="round"
+            stroke-linejoin="round"
+          />
+        </svg>
+      </span>
+      <span
+        :class="this.value ? 'opacity-100 ease-in duration-200' : 'opacity-0 ease-out duration-100'"
+        class="absolute inset-0 h-full w-full flex items-center justify-center transition-opacity"
+        aria-hidden="true"
+      >
+        <svg class="h-3 w-3 text-cyan-500" fill="currentColor" viewBox="0 0 12 12">
+          <path
+            d="M3.707 5.293a1 1 0 00-1.414 1.414l1.414-1.414zM5 8l-.707.707a1 1 0 001.414 0L5 8zm4.707-3.293a1 1 0 00-1.414-1.414l1.414 1.414zm-7.414 2l2 2 1.414-1.414-2-2-1.414 1.414zm3.414 2l4-4-1.414-1.414-4 4 1.414 1.414z"
+          />
+        </svg>
+      </span>
+    </span>
+  </button>
 </template>
 </template>
 
 
 <script>
 <script>
@@ -27,22 +50,5 @@ export default {
       this.value ? this.$emit('off') : this.$emit('on')
       this.value ? this.$emit('off') : this.$emit('on')
     },
     },
   },
   },
-  computed: {
-    indicatorStyles() {
-      return { transform: this.value ? 'translateX(1.5rem)' : 'translateX(0)' }
-    },
-  },
 }
 }
 </script>
 </script>
-
-<style>
-.toggle-background {
-  transition: background-color 0.2s ease;
-}
-
-.toggle-indicator {
-  top: 0.25rem;
-  left: 0.25rem;
-  transition: transform 0.2s ease;
-}
-</style>

+ 2 - 6
resources/js/components/WebauthnKeys.vue

@@ -1,9 +1,7 @@
 <template>
 <template>
   <div>
   <div>
     <div class="mt-6">
     <div class="mt-6">
-      <h3 class="font-bold text-xl">
-        Device Authentication (U2F)
-      </h3>
+      <h3 class="font-bold text-xl">Device Authentication (U2F)</h3>
 
 
       <div class="my-4 w-24 border-b-2 border-grey-200"></div>
       <div class="my-4 w-24 border-b-2 border-grey-200"></div>
 
 
@@ -13,9 +11,7 @@
       </p>
       </p>
 
 
       <div>
       <div>
-        <p class="mb-0" v-if="keys.length === 0">
-          You have not registered any Webauthn Keys.
-        </p>
+        <p class="mb-0" v-if="keys.length === 0">You have not registered any Webauthn Keys.</p>
 
 
         <div class="table w-full text-sm md:text-base" v-if="keys.length > 0">
         <div class="table w-full text-sm md:text-base" v-if="keys.length > 0">
           <div class="table-row">
           <div class="table-row">

+ 3 - 9
resources/js/components/passport/PersonalAccessTokens.vue

@@ -1,8 +1,6 @@
 <template>
 <template>
   <div>
   <div>
-    <h3 class="font-bold text-xl">
-      Information
-    </h3>
+    <h3 class="font-bold text-xl">Information</h3>
 
 
     <div class="mt-4 w-24 border-b-2 border-grey-200"></div>
     <div class="mt-4 w-24 border-b-2 border-grey-200"></div>
 
 
@@ -44,9 +42,7 @@
     </button>
     </button>
 
 
     <div class="mt-6">
     <div class="mt-6">
-      <h3 class="font-bold text-xl">
-        Personal Access Tokens
-      </h3>
+      <h3 class="font-bold text-xl">Personal Access Tokens</h3>
 
 
       <div class="my-4 w-24 border-b-2 border-grey-200"></div>
       <div class="my-4 w-24 border-b-2 border-grey-200"></div>
 
 
@@ -106,9 +102,7 @@
               </li>
               </li>
             </ul>
             </ul>
           </div>
           </div>
-          <label for="create-token-name" class="block text-grey-700 text-sm my-2">
-            Name:
-          </label>
+          <label for="create-token-name" class="block text-grey-700 text-sm my-2"> Name: </label>
           <input
           <input
             v-model="form.name"
             v-model="form.name"
             type="text"
             type="text"

+ 234 - 64
resources/js/pages/Aliases.vue

@@ -11,9 +11,7 @@
           />
           />
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
             {{ totalActive }}
             {{ totalActive }}
-            <p class="text-grey-300 text-sm tracking-wide uppercase">
-              Active
-            </p>
+            <p class="text-grey-300 text-sm tracking-wide uppercase">Active</p>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -27,9 +25,7 @@
           />
           />
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
             {{ totalInactive }}
             {{ totalInactive }}
-            <p class="text-grey-300 text-sm tracking-wide uppercase">
-              Inactive
-            </p>
+            <p class="text-grey-300 text-sm tracking-wide uppercase">Inactive</p>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -43,9 +39,7 @@
           />
           />
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
             {{ totalForwarded }}
             {{ totalForwarded }}
-            <p class="text-grey-300 text-sm tracking-wide uppercase">
-              Emails Forwarded
-            </p>
+            <p class="text-grey-300 text-sm tracking-wide uppercase">Emails Forwarded</p>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -59,9 +53,7 @@
           />
           />
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
             {{ totalBlocked }}
             {{ totalBlocked }}
-            <p class="text-grey-300 text-sm tracking-wide uppercase">
-              Emails Blocked
-            </p>
+            <p class="text-grey-300 text-sm tracking-wide uppercase">Emails Blocked</p>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -75,9 +67,7 @@
           />
           />
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
           <div class="font-bold text-xl md:text-3xl text-indigo-800">
             {{ totalReplies }}
             {{ totalReplies }}
-            <p class="text-grey-300 text-sm tracking-wide uppercase">
-              Email Replies
-            </p>
+            <p class="text-grey-300 text-sm tracking-wide uppercase">Email Replies</p>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -122,7 +112,7 @@
         <div class="block relative mr-4">
         <div class="block relative mr-4">
           <select
           <select
             v-model="showAliases"
             v-model="showAliases"
-            class="block appearance-none w-full text-grey-700 bg-white p-3 pr-8 rounded shadow focus:shadow-outline"
+            class="block appearance-none w-full text-grey-700 bg-white p-3 pr-8 rounded shadow focus:ring"
             required
             required
           >
           >
             <option value="without">Hide Deleted</option>
             <option value="without">Hide Deleted</option>
@@ -148,7 +138,7 @@
             @click="generateAliasModalOpen = true"
             @click="generateAliasModalOpen = true"
             class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none ml-auto"
             class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none ml-auto"
           >
           >
-            Generate New Alias
+            Create New Alias
           </button>
           </button>
         </div>
         </div>
       </div>
       </div>
@@ -182,11 +172,23 @@
         No aliases found for that search!
         No aliases found for that search!
       </div>
       </div>
       <template slot="table-row" slot-scope="props">
       <template slot="table-row" slot-scope="props">
-        <span
-          v-if="props.column.field == 'created_at'"
-          class="tooltip outline-none text-sm"
-          :data-tippy-content="rows[props.row.originalIndex].created_at | formatDate"
-          >{{ props.row.created_at | timeAgo }}
+        <span v-if="props.column.field == 'created_at'" class="flex items-center">
+          <span
+            :class="`bg-${getAliasStatus(props.row).colour}-100`"
+            class="tooltip outline-none h-4 w-4 rounded-full flex items-center justify-center mr-2"
+            :data-tippy-content="getAliasStatus(props.row).status"
+            tabindex="-1"
+          >
+            <span
+              :class="`bg-${getAliasStatus(props.row).colour}-400`"
+              class="h-2 w-2 rounded-full"
+            ></span>
+          </span>
+          <span
+            class="tooltip outline-none text-sm whitespace-nowrap"
+            :data-tippy-content="rows[props.row.originalIndex].created_at | formatDate"
+            >{{ props.row.created_at | timeAgo }}
+          </span>
         </span>
         </span>
         <span v-else-if="props.column.field == 'email'" class="block">
         <span v-else-if="props.column.field == 'email'" class="block">
           <span
           <span
@@ -306,18 +308,44 @@
           />
           />
         </span>
         </span>
         <span v-else class="flex items-center justify-center outline-none" tabindex="-1">
         <span v-else class="flex items-center justify-center outline-none" tabindex="-1">
-          <icon
-            v-if="props.row.deleted_at"
-            name="undo"
-            class="block w-6 h-6 text-grey-300 fill-current cursor-pointer outline-none"
-            @click.native="openRestoreModal(props.row.id)"
-          />
-          <icon
-            v-else
-            name="trash"
-            class="block w-6 h-6 text-grey-300 fill-current cursor-pointer outline-none"
-            @click.native="openDeleteModal(props.row.id)"
-          />
+          <more-options>
+            <div role="none">
+              <span
+                @click="openSendFromModal(props.row)"
+                class="group cursor-pointer flex items-center px-4 py-3 text-sm text-grey-700 hover:bg-grey-100 hover:text-grey-900"
+                role="menuitem"
+              >
+                <icon name="send" class="block mr-3 w-5 h-5 text-grey-300 outline-none" />
+                Send From
+              </span>
+            </div>
+            <div v-if="props.row.deleted_at" role="none">
+              <span
+                @click="openRestoreModal(props.row.id)"
+                class="group cursor-pointer flex items-center px-4 py-3 text-sm text-grey-700 hover:bg-grey-100 hover:text-grey-900"
+                role="menuitem"
+              >
+                <icon
+                  name="undo"
+                  class="block mr-3 w-5 h-5 text-grey-300 fill-current outline-none"
+                />
+                Restore
+              </span>
+            </div>
+            <div v-else role="none">
+              <span
+                @click="openDeleteModal(props.row.id)"
+                class="group cursor-pointer flex items-center px-4 py-3 text-sm text-grey-700 hover:bg-grey-100 hover:text-grey-900"
+                role="menuitem"
+              >
+                <icon
+                  name="trash"
+                  class="block mr-3 w-5 h-5 text-grey-300 fill-current outline-none"
+                />
+                Delete
+              </span>
+            </div>
+          </more-options>
         </span>
         </span>
       </template>
       </template>
     </vue-good-table>
     </vue-good-table>
@@ -328,9 +356,7 @@
           It doesn't look like you have any aliases yet!
           It doesn't look like you have any aliases yet!
         </h1>
         </h1>
         <div class="mx-auto mb-6 w-24 border-b-2 border-grey-200"></div>
         <div class="mx-auto mb-6 w-24 border-b-2 border-grey-200"></div>
-        <p class="mb-4">
-          There are two ways to create new aliases.
-        </p>
+        <p class="mb-4">There are two ways to create new aliases.</p>
         <h3 class="mb-4 text-xl text-indigo-800 font-semibold">
         <h3 class="mb-4 text-xl text-indigo-800 font-semibold">
           Option 1: Create aliases on the fly
           Option 1: Create aliases on the fly
         </h3>
         </h3>
@@ -375,28 +401,23 @@
         <h2
         <h2
           class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
           class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
         >
         >
-          Generate new alias
+          Create new alias
         </h2>
         </h2>
         <p class="mt-4 text-grey-700">
         <p class="mt-4 text-grey-700">
           Other aliases e.g. alias@{{ subdomain }} can also be created automatically when they
           Other aliases e.g. alias@{{ subdomain }} can also be created automatically when they
           receive their first email.
           receive their first email.
         </p>
         </p>
-        <label for="alias_domain" class="block text-grey-700 text-sm my-2">
-          Alias Domain:
-        </label>
+        <label for="alias_domain" class="block text-grey-700 text-sm my-2"> Alias Domain: </label>
         <div class="block relative w-full mb-4">
         <div class="block relative w-full mb-4">
           <select
           <select
             v-model="generateAliasDomain"
             v-model="generateAliasDomain"
             id="alias_domain"
             id="alias_domain"
-            class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline"
+            class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring"
             required
             required
           >
           >
-            <option
-              v-for="domainOption in domainOptions"
-              :key="domainOption"
-              :value="domainOption"
-              >{{ domainOption }}</option
-            >
+            <option v-for="domainOption in domainOptions" :key="domainOption" :value="domainOption">
+              {{ domainOption }}
+            </option>
           </select>
           </select>
           <div
           <div
             class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
             class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
@@ -420,15 +441,16 @@
           <select
           <select
             v-model="generateAliasFormat"
             v-model="generateAliasFormat"
             id="alias_domain"
             id="alias_domain"
-            class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline"
+            class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring"
             required
             required
           >
           >
             <option
             <option
               v-for="formatOption in aliasFormatOptions"
               v-for="formatOption in aliasFormatOptions"
               :key="formatOption.value"
               :key="formatOption.value"
               :value="formatOption.value"
               :value="formatOption.value"
-              >{{ formatOption.label }}</option
             >
             >
+              {{ formatOption.label }}
+            </option>
           </select>
           </select>
           <div
           <div
             class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
             class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
@@ -486,7 +508,7 @@
             :class="generateAliasLoading ? 'cursor-not-allowed' : ''"
             :class="generateAliasLoading ? 'cursor-not-allowed' : ''"
             :disabled="generateAliasLoading"
             :disabled="generateAliasLoading"
           >
           >
-            Generate Alias
+            Create Alias
             <loader v-if="generateAliasLoading" />
             <loader v-if="generateAliasLoading" />
           </button>
           </button>
           <button
           <button
@@ -609,12 +631,114 @@
         </div>
         </div>
       </div>
       </div>
     </Modal>
     </Modal>
+
+    <Modal :open="sendFromAliasModalOpen" @close="closeSendFromModal">
+      <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
+        <h2
+          class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
+        >
+          Send from alias
+        </h2>
+        <p class="mt-4 text-grey-700">
+          Use this to automatically create the correct address to send an email to in order to send
+          an <b>email from this alias</b>.
+        </p>
+        <label for="send_from_alias" class="block text-grey-700 text-sm my-2"> Alias: </label>
+        <input
+          v-model="aliasToSendFrom.email"
+          id="send_from_alias"
+          type="text"
+          class="w-full appearance-none bg-grey-100 border border-transparent text-grey-700 focus:outline-none rounded p-3"
+          disabled
+        />
+        <label for="send_from_alias_destination" class="block text-grey-700 text-sm my-2">
+          Email destination:
+        </label>
+        <p v-show="errors.sendFromAliasDestination" class="mb-3 text-red-500 text-sm">
+          {{ errors.sendFromAliasDestination }}
+        </p>
+        <input
+          v-model="sendFromAliasDestination"
+          id="send_from_alias_destination"
+          type="text"
+          class="w-full appearance-none bg-grey-100 border border-transparent text-grey-700 focus:outline-none rounded p-3"
+          :class="errors.sendFromAliasDestination ? 'border-red-500' : ''"
+          placeholder="Enter email..."
+          autofocus
+        />
+        <div v-if="sendFromAliasEmailToSendTo">
+          <p for="alias_domain" class="block text-grey-700 text-sm my-2">
+            Send your message to this email:
+          </p>
+          <div
+            v-clipboard="() => sendFromAliasEmailToSendTo"
+            v-clipboard:success="setSendFromAliasCopied"
+            class="flex items-center justify-between cursor-pointer text-xs border-t-4 rounded-sm text-green-800 border-green-600 bg-green-100 p-2 mb-3"
+            role="alert"
+          >
+            <span>
+              {{ sendFromAliasEmailToSendTo }}
+            </span>
+            <svg
+              v-if="sendFromAliasCopied"
+              viewBox="0 0 24 24"
+              width="20"
+              height="20"
+              stroke="currentColor"
+              stroke-width="2"
+              fill="none"
+              stroke-linecap="round"
+              stroke-linejoin="round"
+            >
+              <polyline points="9 11 12 14 22 4"></polyline>
+              <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
+            </svg>
+            <svg
+              v-else
+              viewBox="0 0 24 24"
+              width="20"
+              height="20"
+              stroke="currentColor"
+              stroke-width="2"
+              fill="none"
+              stroke-linecap="round"
+              stroke-linejoin="round"
+            >
+              <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
+              <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
+            </svg>
+          </div>
+        </div>
+        <div class="mt-6">
+          <button
+            type="button"
+            @click="displaySendFromAddress(aliasToSendFrom)"
+            class="px-4 py-3 text-cyan-900 font-semibold bg-cyan-400 hover:bg-cyan-300 border border-transparent rounded focus:outline-none"
+            :class="sendFromAliasLoading ? 'cursor-not-allowed' : ''"
+            :disabled="sendFromAliasLoading"
+          >
+            Show address
+            <loader v-if="sendFromAliasLoading" />
+          </button>
+          <button
+            @click="closeSendFromModal"
+            class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
+          >
+            Cancel
+          </button>
+        </div>
+      </div>
+    </Modal>
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
 import Modal from './../components/Modal.vue'
 import Modal from './../components/Modal.vue'
 import Toggle from './../components/Toggle.vue'
 import Toggle from './../components/Toggle.vue'
+import MoreOptions from './../components/MoreOptions.vue'
+import { roundArrow } from 'tippy.js'
+import 'tippy.js/dist/svg-arrow.css'
+import 'tippy.js/dist/tippy.css'
 import tippy from 'tippy.js'
 import tippy from 'tippy.js'
 import Multiselect from 'vue-multiselect'
 import Multiselect from 'vue-multiselect'
 
 
@@ -677,9 +801,7 @@ export default {
     Modal,
     Modal,
     Toggle,
     Toggle,
     Multiselect,
     Multiselect,
-  },
-  mounted() {
-    this.addTooltips()
+    MoreOptions,
   },
   },
   data() {
   data() {
     return {
     return {
@@ -688,9 +810,15 @@ export default {
       aliasIdToEdit: '',
       aliasIdToEdit: '',
       aliasDescriptionToEdit: '',
       aliasDescriptionToEdit: '',
       aliasIdToDelete: '',
       aliasIdToDelete: '',
+      aliasToSendFrom: {},
+      sendFromAliasDestination: '',
+      sendFromAliasEmailToSendTo: '',
+      sendFromAliasCopied: false,
       aliasIdToRestore: '',
       aliasIdToRestore: '',
       deleteAliasLoading: false,
       deleteAliasLoading: false,
       deleteAliasModalOpen: false,
       deleteAliasModalOpen: false,
+      sendFromAliasLoading: false,
+      sendFromAliasModalOpen: false,
       restoreAliasLoading: false,
       restoreAliasLoading: false,
       restoreAliasModalOpen: false,
       restoreAliasModalOpen: false,
       editAliasRecipientsLoading: false,
       editAliasRecipientsLoading: false,
@@ -776,16 +904,11 @@ export default {
         },
         },
       ],
       ],
       rows: this.initialAliases,
       rows: this.initialAliases,
+      tippyInstance: null,
       errors: {},
       errors: {},
     }
     }
   },
   },
   watch: {
   watch: {
-    aliasIdToEdit: _.debounce(function() {
-      this.addTooltips()
-    }, 50),
-    editAliasRecipientsModalOpen: _.debounce(function() {
-      this.addTooltips()
-    }, 50),
     showAliases(value) {
     showAliases(value) {
       this.updateAliases()
       this.updateAliases()
     },
     },
@@ -803,12 +926,16 @@ export default {
   },
   },
   methods: {
   methods: {
     addTooltips() {
     addTooltips() {
-      tippy('.tooltip', {
-        arrow: true,
-        arrowType: 'round',
+      if (this.tippyInstance) {
+        _.each(this.tippyInstance, instance => instance.destroy())
+      }
+
+      this.tippyInstance = tippy('.tooltip', {
+        arrow: roundArrow,
+        allowHTML: true,
       })
       })
     },
     },
-    debounceToolips: _.debounce(function() {
+    debounceToolips: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
     recipientsTooltip(recipients) {
     recipientsTooltip(recipients) {
@@ -822,6 +949,17 @@ export default {
       this.deleteAliasModalOpen = false
       this.deleteAliasModalOpen = false
       this.aliasIdToDelete = ''
       this.aliasIdToDelete = ''
     },
     },
+    openSendFromModal(alias) {
+      this.sendFromAliasDestination = ''
+      this.sendFromAliasEmailToSendTo = ''
+      this.sendFromAliasCopied = false
+      this.sendFromAliasModalOpen = true
+      this.aliasToSendFrom = alias
+    },
+    closeSendFromModal() {
+      this.sendFromAliasModalOpen = false
+      this.aliasToSendFrom = {}
+    },
     openRestoreModal(id) {
     openRestoreModal(id) {
       this.restoreAliasModalOpen = true
       this.restoreAliasModalOpen = true
       this.aliasIdToRestore = id
       this.aliasIdToRestore = id
@@ -1021,6 +1159,21 @@ export default {
           this.error()
           this.error()
         })
         })
     },
     },
+    displaySendFromAddress(alias) {
+      this.errors = {}
+
+      if (!this.validEmail(this.sendFromAliasDestination)) {
+        this.errors.sendFromAliasDestination = 'Valid Email required'
+        return
+      }
+
+      this.sendFromAliasEmailToSendTo = `${
+        alias.local_part
+      }+${this.sendFromAliasDestination.replace('@', '=')}@${alias.domain}`
+    },
+    setSendFromAliasCopied() {
+      this.sendFromAliasCopied = true
+    },
     getAliasEmail(alias) {
     getAliasEmail(alias) {
       return alias.extension
       return alias.extension
         ? `${alias.local_part}+${alias.extension}@${alias.domain}`
         ? `${alias.local_part}+${alias.extension}@${alias.domain}`
@@ -1029,6 +1182,19 @@ export default {
     getAliasLocalPart(alias) {
     getAliasLocalPart(alias) {
       return alias.extension ? `${alias.local_part}+${alias.extension}` : alias.local_part
       return alias.extension ? `${alias.local_part}+${alias.extension}` : alias.local_part
     },
     },
+    getAliasStatus(alias) {
+      if (alias.deleted_at) {
+        return {
+          colour: 'red',
+          status: 'Deleted',
+        }
+      } else {
+        return {
+          colour: alias.active ? 'green' : 'grey',
+          status: alias.active ? 'Active' : 'Inactive',
+        }
+      }
+    },
     sortRecipients(x, y) {
     sortRecipients(x, y) {
       return x.length < y.length ? -1 : x.length > y.length ? 1 : 0
       return x.length < y.length ? -1 : x.length > y.length ? 1 : 0
     },
     },
@@ -1039,6 +1205,10 @@ export default {
       let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))$/
       let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))$/
       return re.test(part)
       return re.test(part)
     },
     },
+    validEmail(email) {
+      let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+      return re.test(email)
+    },
     clipboardSuccess() {
     clipboardSuccess() {
       this.success('Copied to clipboard')
       this.success('Copied to clipboard')
     },
     },

+ 14 - 11
resources/js/pages/Domains.vue

@@ -186,9 +186,7 @@
           To get started all you have to do is add a TXT record to your domain to verify ownership
           To get started all you have to do is add a TXT record to your domain to verify ownership
           and then add the domain here by clicking the button above.
           and then add the domain here by clicking the button above.
         </p>
         </p>
-        <p class="mb-4">
-          The TXT record needs to have the following values:
-        </p>
+        <p class="mb-4">The TXT record needs to have the following values:</p>
         <p class="mb-4">
         <p class="mb-4">
           Type: <b>TXT</b><br />
           Type: <b>TXT</b><br />
           Host: <b>@</b><br />
           Host: <b>@</b><br />
@@ -396,6 +394,9 @@
 <script>
 <script>
 import Modal from './../components/Modal.vue'
 import Modal from './../components/Modal.vue'
 import Toggle from './../components/Toggle.vue'
 import Toggle from './../components/Toggle.vue'
+import { roundArrow } from 'tippy.js'
+import 'tippy.js/dist/svg-arrow.css'
+import 'tippy.js/dist/tippy.css'
 import tippy from 'tippy.js'
 import tippy from 'tippy.js'
 import Multiselect from 'vue-multiselect'
 import Multiselect from 'vue-multiselect'
 
 
@@ -427,9 +428,6 @@ export default {
     Toggle,
     Toggle,
     Multiselect,
     Multiselect,
   },
   },
-  mounted() {
-    this.addTooltips()
-  },
   data() {
   data() {
     return {
     return {
       newDomain: '',
       newDomain: '',
@@ -499,21 +497,26 @@ export default {
         },
         },
       ],
       ],
       rows: this.initialDomains,
       rows: this.initialDomains,
+      tippyInstance: null,
     }
     }
   },
   },
   watch: {
   watch: {
-    domainIdToEdit: _.debounce(function() {
+    domainIdToEdit: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
   },
   },
   methods: {
   methods: {
     addTooltips() {
     addTooltips() {
-      tippy('.tooltip', {
-        arrow: true,
-        arrowType: 'round',
+      if (this.tippyInstance) {
+        _.each(this.tippyInstance, instance => instance.destroy())
+      }
+
+      this.tippyInstance = tippy('.tooltip', {
+        arrow: roundArrow,
+        allowHTML: true,
       })
       })
     },
     },
-    debounceToolips: _.debounce(function() {
+    debounceToolips: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
     validateNewDomain(e) {
     validateNewDomain(e) {

+ 15 - 18
resources/js/pages/Recipients.vue

@@ -55,13 +55,7 @@
           Key
           Key
           <span
           <span
             class="tooltip outline-none"
             class="tooltip outline-none"
-            :data-tippy-content="
-              `Use this to attach recipients to new aliases as they are created e.g. alias+key@${
-                user.username
-              }.anonaddy.com. You can attach multiple recipients by doing alias+2.3.4@${
-                user.username
-              }.anonaddy.com. Separating each key by a full stop.`
-            "
+            :data-tippy-content="`Use this to attach recipients to new aliases as they are created e.g. alias+key@${user.username}.anonaddy.com. You can attach multiple recipients by doing alias+2.3.4@${user.username}.anonaddy.com. Separating each key by a full stop.`"
           >
           >
             <icon name="info" class="inline-block w-4 h-4 text-grey-300 fill-current" />
             <icon name="info" class="inline-block w-4 h-4 text-grey-300 fill-current" />
           </span>
           </span>
@@ -328,6 +322,9 @@
 <script>
 <script>
 import Modal from './../components/Modal.vue'
 import Modal from './../components/Modal.vue'
 import Toggle from './../components/Toggle.vue'
 import Toggle from './../components/Toggle.vue'
+import { roundArrow } from 'tippy.js'
+import 'tippy.js/dist/svg-arrow.css'
+import 'tippy.js/dist/tippy.css'
 import tippy from 'tippy.js'
 import tippy from 'tippy.js'
 
 
 export default {
 export default {
@@ -361,9 +358,6 @@ export default {
     this.defaultRecipient = _.find(this.rows, ['id', this.user.default_recipient_id])
     this.defaultRecipient = _.find(this.rows, ['id', this.user.default_recipient_id])
     this.defaultRecipient.aliases = this.defaultRecipient.aliases.concat(this.aliasesUsingDefault)
     this.defaultRecipient.aliases = this.defaultRecipient.aliases.concat(this.aliasesUsingDefault)
   },
   },
-  mounted() {
-    this.addTooltips()
-  },
   data() {
   data() {
     return {
     return {
       defaultRecipient: {},
       defaultRecipient: {},
@@ -424,21 +418,26 @@ export default {
         },
         },
       ],
       ],
       rows: this.initialRecipients,
       rows: this.initialRecipients,
+      tippyInstance: null,
     }
     }
   },
   },
   watch: {
   watch: {
-    addRecipientKeyModalOpen: _.debounce(function() {
+    addRecipientKeyModalOpen: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
   },
   },
   methods: {
   methods: {
     addTooltips() {
     addTooltips() {
-      tippy('.tooltip', {
-        arrow: true,
-        arrowType: 'round',
+      if (this.tippyInstance) {
+        _.each(this.tippyInstance, instance => instance.destroy())
+      }
+
+      this.tippyInstance = tippy('.tooltip', {
+        arrow: roundArrow,
+        allowHTML: true,
       })
       })
     },
     },
-    debounceToolips: _.debounce(function() {
+    debounceToolips: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
     aliasesTooltip(aliases, isDefault) {
     aliasesTooltip(aliases, isDefault) {
@@ -618,9 +617,7 @@ export default {
           this.recipientKey = ''
           this.recipientKey = ''
           this.addRecipientKeyModalOpen = false
           this.addRecipientKeyModalOpen = false
           this.success(
           this.success(
-            `Key Successfully Added for ${
-              this.recipientToAddKey.email
-            }. Make sure to check the fingerprint is correct!`
+            `Key Successfully Added for ${this.recipientToAddKey.email}. Make sure to check the fingerprint is correct!`
           )
           )
         })
         })
         .catch(error => {
         .catch(error => {

+ 40 - 64
resources/js/pages/Rules.vue

@@ -67,9 +67,7 @@
           It doesn't look like you have any rules yet!
           It doesn't look like you have any rules yet!
         </h1>
         </h1>
         <div class="mx-auto mb-6 w-24 border-b-2 border-grey-200"></div>
         <div class="mx-auto mb-6 w-24 border-b-2 border-grey-200"></div>
-        <p class="mb-4">
-          Click the button above to create a new rule.
-        </p>
+        <p class="mb-4">Click the button above to create a new rule.</p>
       </div>
       </div>
     </div>
     </div>
 
 
@@ -85,9 +83,7 @@
           actions will be added over time.
           actions will be added over time.
         </p>
         </p>
 
 
-        <label for="rule_name" class="block text-grey-700 text-sm my-2">
-          Name:
-        </label>
+        <label for="rule_name" class="block text-grey-700 text-sm my-2"> Name: </label>
         <p v-show="errors.ruleName" class="mb-3 text-red-500 text-sm">
         <p v-show="errors.ruleName" class="mb-3 text-red-500 text-sm">
           {{ errors.ruleName }}
           {{ errors.ruleName }}
         </p>
         </p>
@@ -112,11 +108,11 @@
                 <select
                 <select
                   v-model="createRuleObject.operator"
                   v-model="createRuleObject.operator"
                   id="rule_operator"
                   id="rule_operator"
-                  class="block appearance-none w-full text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                  class="block appearance-none w-full text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                   required
                   required
                 >
                 >
-                  <option value="AND">AND </option>
-                  <option value="OR">OR </option>
+                  <option value="AND">AND</option>
+                  <option value="OR">OR</option>
                 </select>
                 </select>
                 <div
                 <div
                   class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
                   class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
@@ -143,14 +139,15 @@
                       <select
                       <select
                         v-model="createRuleObject.conditions[key].type"
                         v-model="createRuleObject.conditions[key].type"
                         id="rule_condition_types"
                         id="rule_condition_types"
-                        class="block appearance-none w-32 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none w-32 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
                         <option
                         <option
                           v-for="option in conditionTypeOptions"
                           v-for="option in conditionTypeOptions"
                           :key="option.value"
                           :key="option.value"
                           :value="option.value"
                           :value="option.value"
-                          >{{ option.label }}
+                        >
+                          {{ option.label }}
                         </option>
                         </option>
                       </select>
                       </select>
                       <div
                       <div
@@ -177,14 +174,15 @@
                       <select
                       <select
                         v-model="createRuleObject.conditions[key].match"
                         v-model="createRuleObject.conditions[key].match"
                         id="rule_condition_matches"
                         id="rule_condition_matches"
-                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
                         <option
                         <option
                           v-for="option in conditionMatchOptions(createRuleObject, key)"
                           v-for="option in conditionMatchOptions(createRuleObject, key)"
                           :key="option"
                           :key="option"
                           :value="option"
                           :value="option"
-                          >{{ option }}
+                        >
+                          {{ option }}
                         </option>
                         </option>
                       </select>
                       </select>
                       <div
                       <div
@@ -275,9 +273,7 @@
           <div v-for="(action, key) in createRuleObject.actions" :key="key">
           <div v-for="(action, key) in createRuleObject.actions" :key="key">
             <!-- AND/OR operator -->
             <!-- AND/OR operator -->
             <div v-if="key !== 0" class="flex justify-center my-2">
             <div v-if="key !== 0" class="flex justify-center my-2">
-              <div class="relative">
-                AND
-              </div>
+              <div class="relative">AND</div>
             </div>
             </div>
 
 
             <div class="p-2 w-full bg-grey-100">
             <div class="p-2 w-full bg-grey-100">
@@ -290,14 +286,15 @@
                         v-model="createRuleObject.actions[key].type"
                         v-model="createRuleObject.actions[key].type"
                         @change="ruleActionChange(createRuleObject.actions[key])"
                         @change="ruleActionChange(createRuleObject.actions[key])"
                         id="rule_action_types"
                         id="rule_action_types"
-                        class="block appearance-none text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
                         <option
                         <option
                           v-for="option in actionTypeOptions"
                           v-for="option in actionTypeOptions"
                           :key="option.value"
                           :key="option.value"
                           :value="option.value"
                           :value="option.value"
-                          >{{ option.label }}
+                        >
+                          {{ option.label }}
                         </option>
                         </option>
                       </select>
                       </select>
                       <div
                       <div
@@ -319,7 +316,7 @@
                   <span
                   <span
                     v-if="
                     v-if="
                       createRuleObject.actions[key].type === 'subject' ||
                       createRuleObject.actions[key].type === 'subject' ||
-                        createRuleObject.actions[key].type === 'displayFrom'
+                      createRuleObject.actions[key].type === 'displayFrom'
                     "
                     "
                     class="ml-4 flex"
                     class="ml-4 flex"
                   >
                   >
@@ -343,12 +340,12 @@
                       <select
                       <select
                         v-model="createRuleObject.actions[key].value"
                         v-model="createRuleObject.actions[key].value"
                         id="create_rule_action_banner"
                         id="create_rule_action_banner"
-                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
-                        <option selected value="top">Top </option>
-                        <option selected value="bottom">Bottom </option>
-                        <option selected value="off">Off </option>
+                        <option selected value="top">Top</option>
+                        <option selected value="bottom">Bottom</option>
+                        <option selected value="off">Off</option>
                       </select>
                       </select>
                       <div
                       <div
                         class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
                         class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
@@ -423,9 +420,7 @@
           actions will be added over time.
           actions will be added over time.
         </p>
         </p>
 
 
-        <label for="edit_rule_name" class="block text-grey-700 text-sm my-2">
-          Name:
-        </label>
+        <label for="edit_rule_name" class="block text-grey-700 text-sm my-2"> Name: </label>
         <p v-show="errors.ruleName" class="mb-3 text-red-500 text-sm">
         <p v-show="errors.ruleName" class="mb-3 text-red-500 text-sm">
           {{ errors.ruleName }}
           {{ errors.ruleName }}
         </p>
         </p>
@@ -450,11 +445,11 @@
                 <select
                 <select
                   v-model="editRuleObject.operator"
                   v-model="editRuleObject.operator"
                   id="edit_rule_operator"
                   id="edit_rule_operator"
-                  class="block appearance-none w-full text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                  class="block appearance-none w-full text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                   required
                   required
                 >
                 >
-                  <option value="AND">AND </option>
-                  <option value="OR">OR </option>
+                  <option value="AND">AND</option>
+                  <option value="OR">OR</option>
                 </select>
                 </select>
                 <div
                 <div
                   class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
                   class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
@@ -481,14 +476,15 @@
                       <select
                       <select
                         v-model="editRuleObject.conditions[key].type"
                         v-model="editRuleObject.conditions[key].type"
                         id="edit_rule_condition_types"
                         id="edit_rule_condition_types"
-                        class="block appearance-none w-32 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none w-32 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
                         <option
                         <option
                           v-for="option in conditionTypeOptions"
                           v-for="option in conditionTypeOptions"
                           :key="option.value"
                           :key="option.value"
                           :value="option.value"
                           :value="option.value"
-                          >{{ option.label }}
+                        >
+                          {{ option.label }}
                         </option>
                         </option>
                       </select>
                       </select>
                       <div
                       <div
@@ -512,14 +508,15 @@
                       <select
                       <select
                         v-model="editRuleObject.conditions[key].match"
                         v-model="editRuleObject.conditions[key].match"
                         id="edit_rule_condition_matches"
                         id="edit_rule_condition_matches"
-                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
                         <option
                         <option
                           v-for="option in conditionMatchOptions(editRuleObject, key)"
                           v-for="option in conditionMatchOptions(editRuleObject, key)"
                           :key="option"
                           :key="option"
                           :value="option"
                           :value="option"
-                          >{{ option }}
+                        >
+                          {{ option }}
                         </option>
                         </option>
                       </select>
                       </select>
                       <div
                       <div
@@ -607,9 +604,7 @@
           <div v-for="(action, key) in editRuleObject.actions" :key="key">
           <div v-for="(action, key) in editRuleObject.actions" :key="key">
             <!-- AND/OR operator -->
             <!-- AND/OR operator -->
             <div v-if="key !== 0" class="flex justify-center my-2">
             <div v-if="key !== 0" class="flex justify-center my-2">
-              <div class="relative">
-                AND
-              </div>
+              <div class="relative">AND</div>
             </div>
             </div>
 
 
             <div class="p-2 w-full bg-grey-100">
             <div class="p-2 w-full bg-grey-100">
@@ -622,14 +617,15 @@
                         v-model="editRuleObject.actions[key].type"
                         v-model="editRuleObject.actions[key].type"
                         @change="ruleActionChange(editRuleObject.actions[key])"
                         @change="ruleActionChange(editRuleObject.actions[key])"
                         id="rule_action_types"
                         id="rule_action_types"
-                        class="block appearance-none text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
                         <option
                         <option
                           v-for="option in actionTypeOptions"
                           v-for="option in actionTypeOptions"
                           :key="option.value"
                           :key="option.value"
                           :value="option.value"
                           :value="option.value"
-                          >{{ option.label }}
+                        >
+                          {{ option.label }}
                         </option>
                         </option>
                       </select>
                       </select>
                       <div
                       <div
@@ -651,7 +647,7 @@
                   <span
                   <span
                     v-if="
                     v-if="
                       editRuleObject.actions[key].type === 'subject' ||
                       editRuleObject.actions[key].type === 'subject' ||
-                        editRuleObject.actions[key].type === 'displayFrom'
+                      editRuleObject.actions[key].type === 'displayFrom'
                     "
                     "
                     class="ml-4 flex"
                     class="ml-4 flex"
                   >
                   >
@@ -672,12 +668,12 @@
                       <select
                       <select
                         v-model="editRuleObject.actions[key].value"
                         v-model="editRuleObject.actions[key].value"
                         id="edit_rule_action_banner"
                         id="edit_rule_action_banner"
-                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:shadow-outline"
+                        class="block appearance-none w-40 text-grey-700 bg-white p-2 pr-6 rounded shadow focus:ring"
                         required
                         required
                       >
                       >
-                        <option value="top">Top </option>
-                        <option value="bottom">Bottom </option>
-                        <option value="off">Off </option>
+                        <option value="top">Top</option>
+                        <option value="bottom">Bottom</option>
+                        <option value="off">Off</option>
                       </select>
                       </select>
                       <div
                       <div
                         class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
                         class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
@@ -747,9 +743,7 @@
         >
         >
           Delete rule
           Delete rule
         </h2>
         </h2>
-        <p class="mt-4 text-grey-700">
-          Are you sure you want to delete this rule?
-        </p>
+        <p class="mt-4 text-grey-700">Are you sure you want to delete this rule?</p>
         <div class="mt-6">
         <div class="mt-6">
           <button
           <button
             type="button"
             type="button"
@@ -776,7 +770,6 @@
 <script>
 <script>
 import Modal from './../components/Modal.vue'
 import Modal from './../components/Modal.vue'
 import Toggle from './../components/Toggle.vue'
 import Toggle from './../components/Toggle.vue'
-import tippy from 'tippy.js'
 import draggable from 'vuedraggable'
 import draggable from 'vuedraggable'
 
 
 export default {
 export default {
@@ -791,9 +784,6 @@ export default {
     Toggle,
     Toggle,
     draggable,
     draggable,
   },
   },
-  mounted() {
-    this.addTooltips()
-  },
   data() {
   data() {
     return {
     return {
       editRuleObject: {},
       editRuleObject: {},
@@ -869,11 +859,6 @@ export default {
       errors: {},
       errors: {},
     }
     }
   },
   },
-  watch: {
-    editRuleObject: _.debounce(function() {
-      this.addTooltips()
-    }, 50),
-  },
   computed: {
   computed: {
     activeRules() {
     activeRules() {
       return _.filter(this.rows, rule => rule.active)
       return _.filter(this.rows, rule => rule.active)
@@ -891,15 +876,6 @@ export default {
     },
     },
   },
   },
   methods: {
   methods: {
-    addTooltips() {
-      tippy('.tooltip', {
-        arrow: true,
-        arrowType: 'round',
-      })
-    },
-    debounceToolips: _.debounce(function() {
-      this.addTooltips()
-    }, 50),
     openCreateModal() {
     openCreateModal() {
       this.errors = {}
       this.errors = {}
       this.createRuleModalOpen = true
       this.createRuleModalOpen = true

+ 13 - 8
resources/js/pages/Usernames.vue

@@ -311,6 +311,9 @@
 <script>
 <script>
 import Modal from './../components/Modal.vue'
 import Modal from './../components/Modal.vue'
 import Toggle from './../components/Toggle.vue'
 import Toggle from './../components/Toggle.vue'
+import { roundArrow } from 'tippy.js'
+import 'tippy.js/dist/svg-arrow.css'
+import 'tippy.js/dist/tippy.css'
 import tippy from 'tippy.js'
 import tippy from 'tippy.js'
 import Multiselect from 'vue-multiselect'
 import Multiselect from 'vue-multiselect'
 
 
@@ -334,9 +337,6 @@ export default {
     Toggle,
     Toggle,
     Multiselect,
     Multiselect,
   },
   },
-  mounted() {
-    this.addTooltips()
-  },
   data() {
   data() {
     return {
     return {
       newUsername: '',
       newUsername: '',
@@ -399,21 +399,26 @@ export default {
         },
         },
       ],
       ],
       rows: this.initialUsernames,
       rows: this.initialUsernames,
+      tippyInstance: null,
     }
     }
   },
   },
   watch: {
   watch: {
-    usernameIdToEdit: _.debounce(function() {
+    usernameIdToEdit: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
   },
   },
   methods: {
   methods: {
     addTooltips() {
     addTooltips() {
-      tippy('.tooltip', {
-        arrow: true,
-        arrowType: 'round',
+      if (this.tippyInstance) {
+        _.each(this.tippyInstance, instance => instance.destroy())
+      }
+
+      this.tippyInstance = tippy('.tooltip', {
+        arrow: roundArrow,
+        allowHTML: true,
       })
       })
     },
     },
-    debounceToolips: _.debounce(function() {
+    debounceToolips: _.debounce(function () {
       this.addTooltips()
       this.addTooltips()
     }, 50),
     }, 50),
     validateNewUsername(e) {
     validateNewUsername(e) {

+ 13 - 13
resources/js/webauthn.js

@@ -27,7 +27,7 @@ function WebAuthn(notifyCallback = null) {
  * @param {PublicKeyCredentialCreationOptions} publicKey  - see https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialcreationoptions
  * @param {PublicKeyCredentialCreationOptions} publicKey  - see https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialcreationoptions
  * @param {function(PublicKeyCredential)} callback  User callback
  * @param {function(PublicKeyCredential)} callback  User callback
  */
  */
-WebAuthn.prototype.register = function(publicKey, callback) {
+WebAuthn.prototype.register = function (publicKey, callback) {
   let publicKeyCredential = Object.assign({}, publicKey)
   let publicKeyCredential = Object.assign({}, publicKey)
   publicKeyCredential.user.id = this._bufferDecode(publicKey.user.id)
   publicKeyCredential.user.id = this._bufferDecode(publicKey.user.id)
   publicKeyCredential.challenge = this._bufferDecode(this._base64Decode(publicKey.challenge))
   publicKeyCredential.challenge = this._bufferDecode(this._base64Decode(publicKey.challenge))
@@ -56,7 +56,7 @@ WebAuthn.prototype.register = function(publicKey, callback) {
  * @param {PublicKeyCredential} publicKey @see https://www.w3.org/TR/webauthn/#publickeycredential
  * @param {PublicKeyCredential} publicKey @see https://www.w3.org/TR/webauthn/#publickeycredential
  * @param {function(PublicKeyCredential)} callback  User callback
  * @param {function(PublicKeyCredential)} callback  User callback
  */
  */
-WebAuthn.prototype._registerCallback = function(publicKey, callback) {
+WebAuthn.prototype._registerCallback = function (publicKey, callback) {
   let publicKeyCredential = {
   let publicKeyCredential = {
     id: publicKey.id,
     id: publicKey.id,
     type: publicKey.type,
     type: publicKey.type,
@@ -77,7 +77,7 @@ WebAuthn.prototype._registerCallback = function(publicKey, callback) {
  * @param {PublicKeyCredentialRequestOptions} publicKey  - see https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions
  * @param {PublicKeyCredentialRequestOptions} publicKey  - see https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions
  * @param {function(PublicKeyCredential)} callback  User callback
  * @param {function(PublicKeyCredential)} callback  User callback
  */
  */
-WebAuthn.prototype.sign = function(publicKey, callback) {
+WebAuthn.prototype.sign = function (publicKey, callback) {
   let publicKeyCredential = Object.assign({}, publicKey)
   let publicKeyCredential = Object.assign({}, publicKey)
   publicKeyCredential.challenge = this._bufferDecode(this._base64Decode(publicKey.challenge))
   publicKeyCredential.challenge = this._bufferDecode(this._base64Decode(publicKey.challenge))
   if (publicKey.allowCredentials) {
   if (publicKey.allowCredentials) {
@@ -105,7 +105,7 @@ WebAuthn.prototype.sign = function(publicKey, callback) {
  * @param {PublicKeyCredential} publicKey @see https://www.w3.org/TR/webauthn/#publickeycredential
  * @param {PublicKeyCredential} publicKey @see https://www.w3.org/TR/webauthn/#publickeycredential
  * @param {function(PublicKeyCredential)} callback  User callback
  * @param {function(PublicKeyCredential)} callback  User callback
  */
  */
-WebAuthn.prototype._signCallback = function(publicKey, callback) {
+WebAuthn.prototype._signCallback = function (publicKey, callback) {
   let publicKeyCredential = {
   let publicKeyCredential = {
     id: publicKey.id,
     id: publicKey.id,
     type: publicKey.type,
     type: publicKey.type,
@@ -130,7 +130,7 @@ WebAuthn.prototype._signCallback = function(publicKey, callback) {
  * @param {ArrayBuffer} value
  * @param {ArrayBuffer} value
  * @return {string}
  * @return {string}
  */
  */
-WebAuthn.prototype._bufferEncode = function(value) {
+WebAuthn.prototype._bufferEncode = function (value) {
   return window.btoa(String.fromCharCode.apply(null, new Uint8Array(value)))
   return window.btoa(String.fromCharCode.apply(null, new Uint8Array(value)))
 }
 }
 
 
@@ -140,7 +140,7 @@ WebAuthn.prototype._bufferEncode = function(value) {
  * @param {ArrayBuffer} value
  * @param {ArrayBuffer} value
  * @return {string}
  * @return {string}
  */
  */
-WebAuthn.prototype._bufferDecode = function(value) {
+WebAuthn.prototype._bufferDecode = function (value) {
   var t = window.atob(value)
   var t = window.atob(value)
   return Uint8Array.from(t, c => c.charCodeAt(0))
   return Uint8Array.from(t, c => c.charCodeAt(0))
 }
 }
@@ -151,7 +151,7 @@ WebAuthn.prototype._bufferDecode = function(value) {
  * @param {string} input
  * @param {string} input
  * @return {string}
  * @return {string}
  */
  */
-WebAuthn.prototype._base64Decode = function(input) {
+WebAuthn.prototype._base64Decode = function (input) {
   // Replace non-url compatible chars with base64 standard chars
   // Replace non-url compatible chars with base64 standard chars
   input = input.replace(/-/g, '+').replace(/_/g, '/')
   input = input.replace(/-/g, '+').replace(/_/g, '/')
 
 
@@ -175,9 +175,9 @@ WebAuthn.prototype._base64Decode = function(input) {
  * @param {PublicKeyCredentialDescriptor} credentials
  * @param {PublicKeyCredentialDescriptor} credentials
  * @return {PublicKeyCredentialDescriptor}
  * @return {PublicKeyCredentialDescriptor}
  */
  */
-WebAuthn.prototype._credentialDecode = function(credentials) {
+WebAuthn.prototype._credentialDecode = function (credentials) {
   var self = this
   var self = this
-  return credentials.map(function(data) {
+  return credentials.map(function (data) {
     return {
     return {
       id: self._bufferDecode(self._base64Decode(data.id)),
       id: self._bufferDecode(self._base64Decode(data.id)),
       type: data.type,
       type: data.type,
@@ -191,7 +191,7 @@ WebAuthn.prototype._credentialDecode = function(credentials) {
  *
  *
  * @return {bool}
  * @return {bool}
  */
  */
-WebAuthn.prototype.webAuthnSupport = function() {
+WebAuthn.prototype.webAuthnSupport = function () {
   return !(
   return !(
     window.PublicKeyCredential === undefined ||
     window.PublicKeyCredential === undefined ||
     typeof window.PublicKeyCredential !== 'function' ||
     typeof window.PublicKeyCredential !== 'function' ||
@@ -204,7 +204,7 @@ WebAuthn.prototype.webAuthnSupport = function() {
  *
  *
  * @return {string}
  * @return {string}
  */
  */
-WebAuthn.prototype.notSupportedMessage = function() {
+WebAuthn.prototype.notSupportedMessage = function () {
   if (
   if (
     !window.isSecureContext &&
     !window.isSecureContext &&
     window.location.hostname !== 'localhost' &&
     window.location.hostname !== 'localhost' &&
@@ -221,7 +221,7 @@ WebAuthn.prototype.notSupportedMessage = function() {
  * @param {string} message
  * @param {string} message
  * @param {bool} isError
  * @param {bool} isError
  */
  */
-WebAuthn.prototype._notify = function(message, isError) {
+WebAuthn.prototype._notify = function (message, isError) {
   if (this._notifyCallback) {
   if (this._notifyCallback) {
     this._notifyCallback(message, isError)
     this._notifyCallback(message, isError)
   }
   }
@@ -232,7 +232,7 @@ WebAuthn.prototype._notify = function(message, isError) {
  *
  *
  * @param {function(name: string, message: string, isError: bool)} callback
  * @param {function(name: string, message: string, isError: bool)} callback
  */
  */
-WebAuthn.prototype.setNotify = function(callback) {
+WebAuthn.prototype.setNotify = function (callback) {
   this._notifyCallback = callback
   this._notifyCallback = callback
 }
 }
 
 

+ 1 - 1
resources/views/auth/backup_code.blade.php

@@ -27,7 +27,7 @@
                                 Backup Code:
                                 Backup Code:
                             </label>
                             </label>
 
 
-                            <input id="backup_code" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('backup_code') ? ' border border-red-500' : '' }}" name="backup_code" required autofocus>
+                            <input id="backup_code" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('backup_code') ? ' border border-red-500' : '' }}" name="backup_code" required autofocus>
 
 
                             @if ($errors->has('backup_code'))
                             @if ($errors->has('backup_code'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">

+ 3 - 3
resources/views/auth/login.blade.php

@@ -30,7 +30,7 @@
                                 {{ __('Username') }}:
                                 {{ __('Username') }}:
                             </label>
                             </label>
 
 
-                            <input id="username" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required autofocus>
+                            <input id="username" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required autofocus>
 
 
                             @if ($errors->has('username'))
                             @if ($errors->has('username'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -44,7 +44,7 @@
                                 {{ __('Password') }}:
                                 {{ __('Password') }}:
                             </label>
                             </label>
 
 
-                            <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
+                            <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
 
 
                             @if ($errors->has('password'))
                             @if ($errors->has('password'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -61,7 +61,7 @@
                                 </label>
                                 </label>
                             </div>
                             </div>
                             @if (Route::has('password.request'))
                             @if (Route::has('password.request'))
-                                <a class="whitespace-no-wrap no-underline text-sm" href="{{ route('password.request') }}">
+                                <a class="whitespace-nowrap no-underline text-sm" href="{{ route('password.request') }}">
                                     {{ __('Forgot Username/Password?') }}
                                     {{ __('Forgot Username/Password?') }}
                                 </a>
                                 </a>
                             @endif
                             @endif

+ 2 - 2
resources/views/auth/passwords/email.blade.php

@@ -29,7 +29,7 @@
                                 {{ __('Username') }}:
                                 {{ __('Username') }}:
                             </label>
                             </label>
 
 
-                            <input id="username" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required>
+                            <input id="username" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required>
 
 
                             @if ($errors->has('username'))
                             @if ($errors->has('username'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -38,7 +38,7 @@
                             @endif
                             @endif
                         </div>
                         </div>
 
 
-                        <a class="whitespace-no-wrap no-underline text-sm" href="{{ route('username.reminder.show') }}">
+                        <a class="whitespace-nowrap no-underline text-sm" href="{{ route('username.reminder.show') }}">
                             {{ __('Forgot Username?') }}
                             {{ __('Forgot Username?') }}
                         </a>
                         </a>
 
 

+ 3 - 3
resources/views/auth/passwords/reset.blade.php

@@ -25,7 +25,7 @@
                                 {{ __('Username') }}:
                                 {{ __('Username') }}:
                             </label>
                             </label>
 
 
-                            <input id="username" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required autofocus>
+                            <input id="username" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required autofocus>
 
 
                             @if ($errors->has('username'))
                             @if ($errors->has('username'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -39,7 +39,7 @@
                                 {{ __('New Password') }}:
                                 {{ __('New Password') }}:
                             </label>
                             </label>
 
 
-                            <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
+                            <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
 
 
                             @if ($errors->has('password'))
                             @if ($errors->has('password'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -53,7 +53,7 @@
                                 {{ __('Confirm New Password') }}:
                                 {{ __('Confirm New Password') }}:
                             </label>
                             </label>
 
 
-                            <input id="password-confirm" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline" name="password_confirmation" placeholder="********" required>
+                            <input id="password-confirm" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring" name="password_confirmation" placeholder="********" required>
                         </div>
                         </div>
 
 
                     </div>
                     </div>

+ 5 - 5
resources/views/auth/register.blade.php

@@ -24,7 +24,7 @@
                             </label>
                             </label>
 
 
                             <div class="table w-full">
                             <div class="table w-full">
-                                <input id="username" type="text" class="table-cell relative appearance-none bg-grey-100 rounded-l w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required autofocus>
+                                <input id="username" type="text" class="table-cell relative appearance-none bg-grey-100 rounded-l w-full p-3 text-grey-700 focus:ring{{ $errors->has('username') ? ' border-red-500' : '' }}" name="username" value="{{ old('username') }}" placeholder="johndoe" required autofocus>
                                 <div class="py-3 px-2 table-cell align-middle bg-grey-200 rounded-r text-grey-600">
                                 <div class="py-3 px-2 table-cell align-middle bg-grey-200 rounded-r text-grey-600">
                                     .{{ config('anonaddy.domain') }}
                                     .{{ config('anonaddy.domain') }}
                                 </div>
                                 </div>
@@ -45,7 +45,7 @@
                                 Your Real Email Address:
                                 Your Real Email Address:
                             </label>
                             </label>
 
 
-                            <input id="email" type="email" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('email') ? ' border-red-500' : '' }}" name="email" value="{{ old('email') }}" placeholder="johndoe@example.com" required>
+                            <input id="email" type="email" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('email') ? ' border-red-500' : '' }}" name="email" value="{{ old('email') }}" placeholder="johndoe@example.com" required>
 
 
                             <p class="text-xs mt-1 text-grey-600">This is your recipient where emails will be forwarded</p>
                             <p class="text-xs mt-1 text-grey-600">This is your recipient where emails will be forwarded</p>
 
 
@@ -61,7 +61,7 @@
                                 Confirm Email Address:
                                 Confirm Email Address:
                             </label>
                             </label>
 
 
-                            <input id="email-confirm" type="email" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline" name="email_confirmation" value="{{ old('email_confirmation') }}" placeholder="johndoe@example.com" required>
+                            <input id="email-confirm" type="email" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring" name="email_confirmation" value="{{ old('email_confirmation') }}" placeholder="johndoe@example.com" required>
                         </div>
                         </div>
 
 
                         <div class="flex flex-wrap mb-6">
                         <div class="flex flex-wrap mb-6">
@@ -69,7 +69,7 @@
                                 {{ __('Password') }}:
                                 {{ __('Password') }}:
                             </label>
                             </label>
 
 
-                            <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
+                            <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
 
 
                             @if ($errors->has('password'))
                             @if ($errors->has('password'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -86,7 +86,7 @@
                             <div class="flex flex-grow flex-wrap">
                             <div class="flex flex-grow flex-wrap">
                                 <img src="{{captcha_src('mini')}}" class="flex-shrink-0 h-12 w-16 mr-2 mt-2">
                                 <img src="{{captcha_src('mini')}}" class="flex-shrink-0 h-12 w-16 mr-2 mt-2">
 
 
-                                <input id="captcha" type="text" class="flex-grow mt-2 appearance-none bg-grey-100 rounded p-3 text-grey-700 focus:shadow-outline{{ $errors->has('captcha') ? ' border-red-500' : '' }}" name="captcha" placeholder="Enter the text you see" required>
+                                <input id="captcha" type="text" class="flex-grow mt-2 appearance-none bg-grey-100 rounded p-3 text-grey-700 focus:ring{{ $errors->has('captcha') ? ' border-red-500' : '' }}" name="captcha" placeholder="Enter the text you see" required>
                             </div>
                             </div>
 
 
                             @if ($errors->has('captcha'))
                             @if ($errors->has('captcha'))

+ 1 - 1
resources/views/auth/two_factor.blade.php

@@ -29,7 +29,7 @@
                                 {{ __('One Time Token') }}:
                                 {{ __('One Time Token') }}:
                             </label>
                             </label>
 
 
-                            <input id="one_time_password" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('message') ? ' border border-red-500' : '' }}" name="one_time_password" placeholder="123456" required autofocus>
+                            <input id="one_time_password" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('message') ? ' border border-red-500' : '' }}" name="one_time_password" placeholder="123456" required autofocus>
 
 
                             @if ($errors->has('message'))
                             @if ($errors->has('message'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">

+ 2 - 2
resources/views/auth/usernames/email.blade.php

@@ -29,7 +29,7 @@
                                 {{ __('Email') }}:
                                 {{ __('Email') }}:
                             </label>
                             </label>
 
 
-                            <input id="email" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('email') ? ' border-red-500' : '' }}" name="email" value="{{ old('email') }}" placeholder="johndoe@example.com" required>
+                            <input id="email" type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('email') ? ' border-red-500' : '' }}" name="email" value="{{ old('email') }}" placeholder="johndoe@example.com" required>
 
 
                             @if ($errors->has('email'))
                             @if ($errors->has('email'))
                                 <p class="text-red-500 text-xs italic mt-4">
                                 <p class="text-red-500 text-xs italic mt-4">
@@ -39,7 +39,7 @@
                         </div>
                         </div>
 
 
                         @if (Route::has('password.request'))
                         @if (Route::has('password.request'))
-                            <a class="whitespace-no-wrap no-underline text-sm" href="{{ route('password.request') }}">
+                            <a class="whitespace-nowrap no-underline text-sm" href="{{ route('password.request') }}">
                                 {{ __('Forgot Password?') }}
                                 {{ __('Forgot Password?') }}
                             </a>
                             </a>
                         @endif
                         @endif

+ 1 - 1
resources/views/auth/verify.blade.php

@@ -26,7 +26,7 @@
                         <form method="POST" action="{{ route('verification.resend') }}" class="w-full">
                         <form method="POST" action="{{ route('verification.resend') }}" class="w-full">
                             @csrf
                             @csrf
 
 
-                            <button type="submit" class="bg-cyan-400 w-full text-center hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:shadow-outline no-underline mx-auto">
+                            <button type="submit" class="bg-cyan-400 w-full text-center hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:ring no-underline mx-auto">
                                 {{ __('Resend verification email') }}
                                 {{ __('Resend verification email') }}
                             </button>
                             </button>
                         </form>
                         </form>

+ 15 - 15
resources/views/settings/show.blade.php

@@ -70,7 +70,7 @@
                             </label>
                             </label>
 
 
                             <div class="block relative w-full">
                             <div class="block relative w-full">
-                                <select id="default-recipient" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="default_recipient" required>
+                                <select id="default-recipient" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="default_recipient" required>
                                     @foreach($recipientOptions as $recipient)
                                     @foreach($recipientOptions as $recipient)
                                     <option value="{{ $recipient->id }}" {{ $user->email === $recipient->email ? 'selected' : '' }}>{{ $recipient->email }}</option>
                                     <option value="{{ $recipient->id }}" {{ $user->email === $recipient->email ? 'selected' : '' }}>{{ $recipient->email }}</option>
                                     @endforeach
                                     @endforeach
@@ -116,7 +116,7 @@
                             </label>
                             </label>
 
 
                             <div class="block relative w-full">
                             <div class="block relative w-full">
-                                <input id="email" type="email" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="email" value="{{ old('email') ?? $user->email }}">
+                                <input id="email" type="email" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="email" value="{{ old('email') ?? $user->email }}">
                             </div>
                             </div>
 
 
                             @if ($errors->has('email'))
                             @if ($errors->has('email'))
@@ -132,7 +132,7 @@
                             </label>
                             </label>
 
 
                             <div class="block relative w-full">
                             <div class="block relative w-full">
-                                <input id="email_confirmation" type="email" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="email_confirmation">
+                                <input id="email_confirmation" type="email" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="email_confirmation">
                             </div>
                             </div>
                         </div>
                         </div>
 
 
@@ -165,7 +165,7 @@
                         </label>
                         </label>
 
 
                         <div class="block relative w-full">
                         <div class="block relative w-full">
-                            <select id="default-alias-domain" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="domain" required>
+                            <select id="default-alias-domain" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="domain" required>
                                 @foreach($user->domainOptions() as $domainOption)
                                 @foreach($user->domainOptions() as $domainOption)
                                 <option value="{{ $domainOption }}" {{ $user->default_alias_domain === $domainOption ? 'selected' : '' }}>{{ $domainOption }}</option>
                                 <option value="{{ $domainOption }}" {{ $user->default_alias_domain === $domainOption ? 'selected' : '' }}>{{ $domainOption }}</option>
                                 @endforeach
                                 @endforeach
@@ -209,7 +209,7 @@
                         </label>
                         </label>
 
 
                         <div class="block relative w-full">
                         <div class="block relative w-full">
-                            <select id="default-alias-format" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="format" required>
+                            <select id="default-alias-format" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="format" required>
                                 <option value="uuid" {{ $user->default_alias_format === 'uuid' ? 'selected' : '' }}>UUID</option>
                                 <option value="uuid" {{ $user->default_alias_format === 'uuid' ? 'selected' : '' }}>UUID</option>
                                 <option value="random_words" {{ $user->default_alias_format === 'random_words' ? 'selected' : '' }}>Random Words</option>
                                 <option value="random_words" {{ $user->default_alias_format === 'random_words' ? 'selected' : '' }}>Random Words</option>
                                 <option value="custom" {{ $user->default_alias_format === 'custom' ? 'selected' : '' }}>Custom</option>
                                 <option value="custom" {{ $user->default_alias_format === 'custom' ? 'selected' : '' }}>Custom</option>
@@ -250,7 +250,7 @@
                             {{ __('Current Password') }}:
                             {{ __('Current Password') }}:
                         </label>
                         </label>
 
 
-                        <input id="current" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('current') ? ' border-red-500' : '' }}" name="current" placeholder="********" required>
+                        <input id="current" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('current') ? ' border-red-500' : '' }}" name="current" placeholder="********" required>
 
 
                         @if ($errors->has('current'))
                         @if ($errors->has('current'))
                             <p class="text-red-500 text-xs italic mt-4">
                             <p class="text-red-500 text-xs italic mt-4">
@@ -264,7 +264,7 @@
                             {{ __('New Password') }}:
                             {{ __('New Password') }}:
                         </label>
                         </label>
 
 
-                        <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
+                        <input id="password" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('password') ? ' border-red-500' : '' }}" name="password" placeholder="********" required>
 
 
                         @if ($errors->has('password'))
                         @if ($errors->has('password'))
                             <p class="text-red-500 text-xs italic mt-4">
                             <p class="text-red-500 text-xs italic mt-4">
@@ -278,7 +278,7 @@
                             {{ __('Confirm New Password') }}:
                             {{ __('Confirm New Password') }}:
                         </label>
                         </label>
 
 
-                        <input id="password-confirm" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline" name="password_confirmation" placeholder="********" required>
+                        <input id="password-confirm" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring" name="password_confirmation" placeholder="********" required>
                     </div>
                     </div>
 
 
                 </div>
                 </div>
@@ -336,7 +336,7 @@
                                     {{ __('Current Password') }}:
                                     {{ __('Current Password') }}:
                                 </label>
                                 </label>
 
 
-                                <input id="current_password_2fa" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline{{ $errors->has('current_password_2fa') ? ' border-red-500' : '' }}" name="current_password_2fa" placeholder="********" required>
+                                <input id="current_password_2fa" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring{{ $errors->has('current_password_2fa') ? ' border-red-500' : '' }}" name="current_password_2fa" placeholder="********" required>
 
 
                                 @if ($errors->has('current_password_2fa'))
                                 @if ($errors->has('current_password_2fa'))
                                     <p class="text-red-500 text-xs italic mt-4">
                                     <p class="text-red-500 text-xs italic mt-4">
@@ -396,7 +396,7 @@
                                 </label>
                                 </label>
 
 
                                 <div class="block relative w-full">
                                 <div class="block relative w-full">
-                                    <input id="two_factor_token" type="text" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="two_factor_token" placeholder="123456" />
+                                    <input id="two_factor_token" type="text" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="two_factor_token" placeholder="123456" />
                                 </div>
                                 </div>
 
 
                                 @if ($errors->has('two_factor_token'))
                                 @if ($errors->has('two_factor_token'))
@@ -466,7 +466,7 @@
                         </label>
                         </label>
 
 
                         <div class="block relative w-full">
                         <div class="block relative w-full">
-                            <select id="catch_all" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="catch_all" required>
+                            <select id="catch_all" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="catch_all" required>
                                 <option value="1" {{ $user->catch_all ? 'selected' : '' }}>Enabled</option>
                                 <option value="1" {{ $user->catch_all ? 'selected' : '' }}>Enabled</option>
                                 <option value="0" {{ ! $user->catch_all ? 'selected' : '' }}>Disabled</option>
                                 <option value="0" {{ ! $user->catch_all ? 'selected' : '' }}>Disabled</option>
                             </select>
                             </select>
@@ -509,7 +509,7 @@
                         </label>
                         </label>
 
 
                         <div class="block relative w-full">
                         <div class="block relative w-full">
-                            <input id="from_name" type="text" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="from_name" value="{{ $user->from_name }}" placeholder="John Doe" />
+                            <input id="from_name" type="text" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="from_name" value="{{ $user->from_name }}" placeholder="John Doe" />
                         </div>
                         </div>
 
 
                         @if ($errors->has('from_name'))
                         @if ($errors->has('from_name'))
@@ -546,7 +546,7 @@
                         </label>
                         </label>
 
 
                         <div class="block relative w-full">
                         <div class="block relative w-full">
-                            <select id="banner_location" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="banner_location" required>
+                            <select id="banner_location" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="banner_location" required>
                                 <option value="top" {{ $user->banner_location === 'top' ? 'selected' : '' }}>Top</option>
                                 <option value="top" {{ $user->banner_location === 'top' ? 'selected' : '' }}>Top</option>
                                 <option value="bottom" {{ $user->banner_location === 'bottom' ? 'selected' : '' }}>Bottom</option>
                                 <option value="bottom" {{ $user->banner_location === 'bottom' ? 'selected' : '' }}>Bottom</option>
                                 <option value="off" {{ $user->banner_location === 'off' ? 'selected' : '' }}>Off</option>
                                 <option value="off" {{ $user->banner_location === 'off' ? 'selected' : '' }}>Off</option>
@@ -592,7 +592,7 @@
                         </label>
                         </label>
 
 
                         <div class="block relative w-full">
                         <div class="block relative w-full">
-                            <input id="email_subject" type="text" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline" name="email_subject" value="{{ $user->email_subject }}" placeholder="The subject" />
+                            <input id="email_subject" type="text" class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:ring" name="email_subject" value="{{ $user->email_subject }}" placeholder="The subject" />
                         </div>
                         </div>
 
 
                         @if ($errors->has('email_subject'))
                         @if ($errors->has('email_subject'))
@@ -677,7 +677,7 @@
                             {{ __('Enter your password to continue') }}:
                             {{ __('Enter your password to continue') }}:
                         </label>
                         </label>
 
 
-                        <input id="current-password-delete" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:outline-none focus:shadow-outline{{ $errors->has('current_password_delete') ? ' border-red-500' : '' }}" name="current_password_delete" placeholder="********" required>
+                        <input id="current-password-delete" type="password" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:outline-none focus:ring{{ $errors->has('current_password_delete') ? ' border-red-500' : '' }}" name="current_password_delete" placeholder="********" required>
 
 
                         @if ($errors->has('current_password_delete'))
                         @if ($errors->has('current_password_delete'))
                             <p class="text-red-500 text-xs italic mt-4">
                             <p class="text-red-500 text-xs italic mt-4">

+ 1 - 1
resources/views/vendor/webauthn/register.blade.php

@@ -40,7 +40,7 @@
                         <label for="name" class="block text-grey-700 text-sm mb-2">
                         <label for="name" class="block text-grey-700 text-sm mb-2">
                             Name:
                             Name:
                         </label>
                         </label>
-                        <input type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:shadow-outline" name="name" id="name" placeholder="Yubikey" required autofocus>
+                        <input type="text" class="appearance-none bg-grey-100 rounded w-full p-3 text-grey-700 focus:ring" name="name" id="name" placeholder="Yubikey" required autofocus>
 
 
                         @if ($errors->has('name'))
                         @if ($errors->has('name'))
                             <p class="text-red-500 text-xs italic mt-4">
                             <p class="text-red-500 text-xs italic mt-4">

+ 21 - 5
tailwind.config.js

@@ -1,8 +1,4 @@
 module.exports = {
 module.exports = {
-  future: {
-    removeDeprecatedGapUtilities: true,
-    purgeLayersByDefault: true,
-  },
   purge: {
   purge: {
     content: [
     content: [
       'app/**/*.php',
       'app/**/*.php',
@@ -14,7 +10,15 @@ module.exports = {
 
 
     // These options are passed through directly to PurgeCSS
     // These options are passed through directly to PurgeCSS
     options: {
     options: {
-      whitelistPatterns: [/-active$/, /-enter$/, /-leave-to$/, /show$/],
+      safelist: [
+        /-active$/,
+        /-enter$/,
+        /-leave-to$/,
+        /show$/,
+        'bg-green-400',
+        'bg-red-400',
+        'bg-grey-400',
+      ],
     },
     },
   },
   },
   theme: {
   theme: {
@@ -107,6 +111,18 @@ module.exports = {
         900: '#014807',
         900: '#014807',
       },
       },
     },
     },
+    fontSize: {
+      xs: '0.75rem',
+      sm: '0.875rem',
+      base: '1rem',
+      lg: '1.125rem',
+      xl: '1.25rem',
+      '2xl': '1.5rem',
+      '3xl': '1.875rem',
+      '4xl': '2.25rem',
+      '5xl': '3rem',
+      '6xl': '4rem',
+    },
     container: {
     container: {
       center: true,
       center: true,
       padding: '1.5rem',
       padding: '1.5rem',

+ 1 - 8
webpack.mix.js

@@ -3,14 +3,7 @@ let mix = require('laravel-mix')
 mix
 mix
   .js('resources/js/app.js', 'public/js')
   .js('resources/js/app.js', 'public/js')
   .js('resources/js/webauthn.js', 'public/js')
   .js('resources/js/webauthn.js', 'public/js')
-  .postCss('resources/css/app.css', 'public/css')
-  .options({
-    postCss: [
-      require('postcss-import')(),
-      require('tailwindcss')('./tailwind.config.js'),
-      require('postcss-nesting')(),
-    ],
-  })
+  .postCss('resources/css/app.css', 'public/css', [require('tailwindcss')])
 
 
 if (mix.inProduction()) {
 if (mix.inProduction()) {
   mix.version()
   mix.version()

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels