feat: UI cleanup

This commit is contained in:
Nicholas Ciechanowski 2023-10-07 16:14:41 +11:00
parent 5c5ec88dfd
commit 6441a520a0
23 changed files with 248 additions and 214 deletions

View File

@ -11,7 +11,7 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function register(): void public function register(): void
{ {
// \Livewire\Livewire::forceAssetInjection();
} }
/** /**

View File

@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
* *
* @var string * @var string
*/ */
public const HOME = '/home'; public const HOME = '/dashboard';
/** /**
* Define your route model bindings, pattern filters, and other route configuration. * Define your route model bindings, pattern filters, and other route configuration.

View File

@ -1,3 +1,3 @@
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150']) }}> <button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-nexi-black transition ease-in-out duration-150']) }}>
{{ $slot }} {{ $slot }}
</button> </button>

View File

@ -0,0 +1,22 @@
<div class="flex items-center">
<template x-if="darkMode === 'dark'">
<button x-on:click="darkMode = 'light'" class="pl-6">
<svg xmlns="http://www.w3.org/2000/svg"
x-bind:class="{'border-2 border-red/50': darkMode === 'light'}"
class="w-6 h-6 p-1 text-gray-700 transition rounded-full cursor-pointer bg-gray-50 hover:bg-gray-200" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<span class="sr-only">light</span>
</button>
</template>
<template x-if="darkMode !== 'dark'">
<button x-on:click="darkMode = 'dark'" class="pl-6">
<svg xmlns="http://www.w3.org/2000/svg"
x-bind:class="{'border-2 border-red/50': darkMode === 'dark'}"
class="w-6 h-6 p-1 text-gray-100 transition bg-gray-700 rounded-full cursor-pointer dark:hover:bg-gray-600" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
</svg>
<span class="sr-only">dark</span>
</button>
</template>
</div>

View File

@ -1 +1 @@
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out']) }}>{{ $slot }}</a> <a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-nexi-black focus:outline-none focus:bg-gray-100 dark:focus:bg-nexi-black transition duration-150 ease-in-out']) }}>{{ $slot }}</a>

View File

@ -59,12 +59,12 @@ $maxWidth = [
x-transition:leave-start="opacity-100" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0" x-transition:leave-end="opacity-0"
> >
<div class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75"></div> <div class="absolute inset-0 bg-gray-500 dark:bg-nexi-black opacity-75"></div>
</div> </div>
<div <div
x-show="show" x-show="show"
class="mb-6 bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto" class="mb-6 bg-white dark:bg-nexi-black rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto"
x-transition:enter="ease-out duration-300" x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"

View File

@ -2,7 +2,7 @@
@php @php
$classes = ($active ?? false) $classes = ($active ?? false)
? 'inline-flex items-center px-1 pt-1 border-b-2 border-nexi-red text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-nexi-red transition duration-150 ease-in-out' ? 'inline-flex items-center px-1 pt-1 border-b-2 border-nexi-red text-sm font-medium leading-5 text-nexi-black focus:outline-none focus:border-nexi-red transition duration-150 ease-in-out'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out'; : 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out';
@endphp @endphp

View File

@ -2,8 +2,8 @@
@php @php
$classes = ($active ?? false) $classes = ($active ?? false)
? 'block w-full pl-3 pr-4 py-2 border-l-4 border-indigo-400 dark:border-indigo-600 text-left text-base font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:outline-none focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300 transition duration-150 ease-in-out' ? 'block w-full pl-3 pr-4 py-2 border-l-4 border-indigo-400 dark:border-indigo-600 text-left text-sm font-medium text-nexi-black dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:outline-none focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300 transition duration-150 ease-in-out'
: 'block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-left text-base font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-gray-800 dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out'; : 'block w-full pl-3 pr-4 py-2 border-l-4 border-transparent text-left text-sm font-medium text-gray-600 dark:text-gray-400 hover:text-nexi-black dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-nexi-black dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out';
@endphp @endphp
<a {{ $attributes->merge(['class' => $classes]) }}> <a {{ $attributes->merge(['class' => $classes]) }}>

View File

@ -1,3 +1,3 @@
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150']) }}> <button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white dark:bg-nexi-black border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-nexi-black disabled:opacity-25 transition ease-in-out duration-150']) }}>
{{ $slot }} {{ $slot }}
</button> </button>

View File

@ -0,0 +1,8 @@
@props(['route'])
<a {{ $attributes }} class="
{{ Route::is($route)
? 'text-nexi-red bg-gray-50 dark:text-nexi-purple dark:bg-zinc-800'
: 'text-nexi-black dark:text-nexi-grey hover:text-nexi-red dark:hover:text-nexi-red hover:bg-gray-100 dark:hover:bg-zinc-500' }}
group flex items-center px-2 py-2 text-base font-medium rounded-md"
>{{ $slot }}</a>

View File

@ -0,0 +1,51 @@
<div>
<div class="flex h-16 shrink-0 items-center border-b border-gray-200">
<a href="{{ route('dashboard') }}" wire:navigate>
<img class="h-12 w-auto" src="https://benjamyn.love/PriceyBot.png" alt="">
</a>
</div>
<nav class="flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-7">
<li class="border-b border-gray-200">
<div class="text-xs font-semibold leading-6 text-gray-400">User Menu</div>
<ul role="list" class="-mx-2 mt-2 space-y-1">
<ul role="list" class="-mx-2 space-y-1">
<li>
{{-- TODO: fill with SVG icons to make it pretty --}}
{{-- <svg class="h-6 w-6 shrink-0 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">--}}
{{-- <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />--}}
{{-- </svg>--}}
<x-sidebar-nav :href="route('dashboard')" route="dashboard">First Page</x-sidebar-nav>
</li>
<li>
{{-- TODO: fill with SVG icons to make it pretty --}}
{{-- <x-sidebar-nav :href="route('u-2')" route="u-2">Second Page</x-sidebar-nav>--}}
</li>
<li>
{{-- TODO: fill with SVG icons to make it pretty --}}
{{-- <x-sidebar-nav :href="route('u-3')" route="u-3">Third Page</x-sidebar-nav>--}}
</li>
</ul>
</ul>
</li>
<li>
<div class="text-xs font-semibold leading-6 text-gray-400">Admin Menu</div>
<ul role="list" class="-mx-2 mt-2 space-y-1">
<li>
{{-- TODO: fill with SVG icons to make it pretty --}}
{{-- <x-sidebar-nav :href="route('a-1')" route="a-1">First Page</x-sidebar-nav>--}}
</li>
<li>
{{-- TODO: fill with SVG icons to make it pretty --}}
{{-- <x-sidebar-nav :href="route('a-2')" route="a-2">Second Page</x-sidebar-nav>--}}
</li>
<li>
{{-- TODO: fill with SVG icons to make it pretty --}}
{{-- <x-sidebar-nav :href="route('a-3')" route="a-3">Third Page</x-sidebar-nav>--}}
</li>
</ul>
</li>
</ul>
</nav>
</div>

View File

@ -1,16 +1,8 @@
<x-app-layout> <x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Dashboard') }}
</h2>
</x-slot>
<div class="py-12"> <div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 text-nexi-black dark:text-gray-100">
<div class="p-6 text-gray-900 dark:text-gray-100"> {{ __("You're logged in!") }}
{{ __("You're logged in!") }}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
x-data="{
darkMode: localStorage.getItem('darkMode') ||
localStorage.setItem('darkMode', 'system')
}"
x-init="$watch('darkMode', val => localStorage.setItem('darkMode', val))"
x-bind:class="{'dark': darkMode === 'dark' || (darkMode === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)}"
>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -14,23 +21,67 @@
<!-- Scripts --> <!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
</head> </head>
<body class="font-sans antialiased"> <body class="antialiased bg-nexi-primary dark:bg-nexi-primary-dark font-sans text-nexi-black transition-colors duration-300">
<div class="min-h-screen bg-gray-100 dark:bg-gray-900"> <div x-data="{ sidebarOpen: false }">
<livewire:layout.navigation /> <div class="relative z-50 lg:hidden" role="dialog" aria-modal="true">
{{-- TODO: Look into why the fuck does this not work? mobile views seem to not work with livewire clicks??? --}}
<div x-show="sidebarOpen"
x-transition:enter="transition-opacity ease-linear duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-linear duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-nexi-black/80"></div>
<!-- Page Heading --> <div class="fixed inset-0 flex">
@if (isset($header)) <div x-show="sidebarOpen"
<header class="bg-white dark:bg-gray-800 shadow"> x-transition:enter="transition ease-in-out duration-300 transform"
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> x-transition:enter-start="-translate-x-full"
{{ $header }} x-transition:enter-end="translate-x-0"
x-transition:leave="transition ease-in-out duration-300 transform"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="-translate-x-full"
class="relative mr-16 flex w-full max-w-xs flex-1">
<div x-show="sidebarOpen"
x-transition:enter="ease-in-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in-out duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="absolute left-full top-0 flex w-16 justify-center pt-5">
<button type="button" class="-m-2.5 p-2.5" @click="sidebarOpen = false">
<svg class="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="flex grow flex-col gap-y-5 overflow-y-auto px-6 pb-4">
<x-sidebar/>
</div>
</div> </div>
</header> </div>
@endif </div>
<!-- Page Content --> <!-- Static sidebar for desktop -->
<main> <div class="hidden lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-72 lg:flex-col">
{{ $slot }} <div class="flex grow flex-col gap-y-5 overflow-y-auto border-r border-gray-200 px-6 pb-4">
</main> <x-sidebar/>
</div>
</div>
<div class="lg:pl-72">
<livewire:layout.navigation />
<main class="py-10">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
{{ $slot }}
</div>
</main>
</div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -21,7 +21,7 @@
<!-- Scripts --> <!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
</head> </head>
<body class="antialiased bg-nexi-primary dark:bg-nexi-primary-dark font-sans text-gray-900"> <body class="antialiased bg-nexi-primary dark:bg-nexi-primary-dark font-sans text-nexi-black transition-colors duration-300">
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 "> <div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 ">
{{-- TODO: REPLACE WITH OUR LOGO --}} {{-- TODO: REPLACE WITH OUR LOGO --}}
<div> <div>

View File

@ -1,35 +1,20 @@
<div class="sm:fixed sm:top-0 sm:right-0 p-6 text-right z-10"> <div class="sm:fixed sm:top-0 sm:right-0 p-6 text-right z-10 bg-nexi-primary dark:bg-nexi-primary-dark transition-colors duration-300">
@auth @auth
<a href="{{ url('/home') }}" <div class="pr-6 flex">
class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500" <a href="{{ url('/dashboard') }}"
wire:navigate class="font-semibold text-gray-600 hover:text-nexi-black dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500"
>Dashboard</a> wire:navigate
>Dashboard</a>
<x-darkmode/>
</div>
@else @else
<div class="pr-6"> <div class="pr-6 flex">
<a href="{{ route('login') }}" <a href="{{ route('login') }}"
class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500" class="font-semibold text-gray-600 hover:text-nexi-black dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500"
wire:navigate>Log in</a> wire:navigate>Log in</a>
<template x-if="darkMode === 'dark'"> <x-darkmode/>
<button x-on:click="darkMode = 'light'" class="pl-6">
<svg xmlns="http://www.w3.org/2000/svg"
x-bind:class="{'border-2 border-red/50': darkMode === 'light'}"
class="w-6 h-6 p-1 text-gray-700 transition rounded-full cursor-pointer bg-gray-50 hover:bg-gray-200" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<span class="sr-only">light</span>
</button>
</template>
<template x-if="darkMode !== 'dark'">
<button x-on:click="darkMode = 'dark'" class="pl-6">
<svg xmlns="http://www.w3.org/2000/svg"
x-bind:class="{'border-2 border-red/50': darkMode === 'dark'}"
class="w-6 h-6 p-1 text-gray-100 transition bg-gray-700 rounded-full cursor-pointer dark:hover:bg-gray-600" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
</svg>
<span class="sr-only">dark</span>
</button>
</template>
</div> </div>
@endauth @endauth
</div> </div>

View File

@ -15,94 +15,70 @@ new class extends Component
} }
}; ?> }; ?>
<nav x-data="{ open: false }" class="bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700"> <nav x-data="{ openProfile : false }" class="sticky top-0 z-40 lg:mx-auto lg:max-w-7xl lg:px-8 bg-nexi-primary dark:bg-nexi-primary-dark transition-colors duration-300">
<!-- Primary Navigation Menu --> <div class="flex h-16 items-center gap-x-4 border-b border-gray-200 px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-0 lg:shadow-none">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <button type="button" class="-m-2.5 p-2.5 text-gray-700 lg:hidden" @click="sidebarOpen = true">
<div class="flex justify-between h-16"> <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<div class="flex"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
<!-- Logo --> </svg>
<div class="shrink-0 flex items-center"> </button>
<a href="{{ route('dashboard') }}" wire:navigate>
<x-application-logo class="block h-9 w-auto fill-current text-gray-800 dark:text-gray-200" /> <!-- Separator -->
</a> <div class="h-6 w-px bg-gray-200 lg:hidden" aria-hidden="true"></div>
<div class="flex flex-1 gap-x-4 self-stretch lg:gap-x-6 flex-row-reverse">
<div class="flex items-center gap-x-4 lg:gap-x-6">
{{-- TODO: Hide this on mobile and put in under user menu? maybe move to side bar--}}
<x-darkmode/>
<!-- Separator -->
<div class="hidden lg:block lg:h-6 lg:w-px lg:bg-gray-200" aria-hidden="true"></div>
<!-- Profile dropdown -->
<div class="relative">
<button @click="openProfile = ! openProfile"
type="button"
class="-m-1.5 flex items-center p-1.5"
id="user-menu-button"
aria-expanded="false"
aria-haspopup="true">
{{-- TODO: Add User Image URL here --}}
<img class="h-8 w-8 rounded-full bg-gray-50" src="" alt="">
<span class="hidden lg:flex lg:items-center">
<span class="ml-4 text-base font-semibold leading-6 text-nexi-black dark:text-nexi-grey" aria-hidden="true" x-data="{ name: '{{ auth()->user()->name }}' }" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></span>
<svg class="ml-2 h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd" />
</svg>
</span>
</button>
<div class="absolute right-0 z-10 mt-2.5 w-32 origin-top-right rounded-md bg-nexi-primary dark:bg-nexi-primary-dark py-2 shadow-lg ring-1 ring-nexi-black/5 dark:ring-nexi-grey focus:outline-none"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu-button"
tabindex="-1"
x-show="openProfile"
x-transition:enter="transition ease-out duration-100 transform opacity-0 scale-95"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75 transform opacity-100 scale-100"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95"
>
<div class="mt-3 space-y-1 text-sm">
<x-responsive-nav-link u :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-responsive-nav-link>
<button wire:click="logout" class="w-full text-left">
<x-responsive-nav-link>
{{ __('Log Out') }}
</x-responsive-nav-link>
</button>
</div>
</div>
</div> </div>
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</x-nav-link>
</div>
</div>
<!-- Settings Dropdown -->
<div class="hidden sm:flex sm:items-center sm:ml-6">
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none transition ease-in-out duration-150">
<div x-data="{ name: '{{ auth()->user()->name }}' }" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="ml-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-dropdown-link>
<!-- Authentication -->
<button wire:click="logout" class="w-full text-left">
<x-dropdown-link>
{{ __('Log Out') }}
</x-dropdown-link>
</button>
</x-slot>
</x-dropdown>
</div>
<!-- Hamburger -->
<div class="-mr-2 flex items-center sm:hidden">
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-900 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-500 dark:focus:text-gray-400 transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Responsive Navigation Menu -->
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
<div class="pt-2 pb-3 space-y-1">
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')" wire:navigate>
{{ __('Dashboard') }}
</x-responsive-nav-link>
</div>
<!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-600">
<div class="px-4">
<div class="font-medium text-base text-gray-800 dark:text-gray-200" x-data="{ name: '{{ auth()->user()->name }}' }" x-text="name" x-on:profile-updated.window="name = $event.detail.name"></div>
<div class="font-medium text-sm text-gray-500">{{ auth()->user()->email }}</div>
</div>
<div class="mt-3 space-y-1">
<x-responsive-nav-link :href="route('profile')" wire:navigate>
{{ __('Profile') }}
</x-responsive-nav-link>
<!-- Authentication -->
<button wire:click="logout" class="w-full text-left">
<x-responsive-nav-link>
{{ __('Log Out') }}
</x-responsive-nav-link>
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -26,6 +26,7 @@ new #[Layout('layouts.guest')] class extends Component
$this->ensureIsNotRateLimited(); $this->ensureIsNotRateLimited();
if (!auth()->attempt($this->only(['email', 'password'], $this->remember))) { if (!auth()->attempt($this->only(['email', 'password'], $this->remember))) {
RateLimiter::hit($this->throttleKey()); RateLimiter::hit($this->throttleKey());
@ -113,7 +114,7 @@ new #[Layout('layouts.guest')] class extends Component
<div class="flex items-center justify-end mt-4"> <div class="flex items-center justify-end mt-4">
@if (Route::has('password.request')) @if (Route::has('password.request'))
<a class="underline text-sm text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-nexi-red" <a class="underline text-sm text-gray-600 dark:text-gray-300 hover:text-nexi-black dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-nexi-red"
href="{{ route('password.request') }}" href="{{ route('password.request') }}"
wire:navigate> wire:navigate>
{{ __('Forgot your password?') }} {{ __('Forgot your password?') }}

View File

@ -23,7 +23,7 @@ new class extends Component
<section class="space-y-6"> <section class="space-y-6">
<header> <header>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> <h2 class="text-lg font-medium text-nexi-black dark:text-gray-100">
{{ __('Delete Account') }} {{ __('Delete Account') }}
</h2> </h2>
@ -40,7 +40,7 @@ new class extends Component
<x-modal name="confirm-user-deletion" :show="$errors->isNotEmpty()" focusable> <x-modal name="confirm-user-deletion" :show="$errors->isNotEmpty()" focusable>
<form wire:submit="deleteUser" class="p-6"> <form wire:submit="deleteUser" class="p-6">
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> <h2 class="text-lg font-medium text-nexi-black dark:text-gray-100">
{{ __('Are you sure you want to delete your account?') }} {{ __('Are you sure you want to delete your account?') }}
</h2> </h2>

View File

@ -36,7 +36,7 @@ new class extends Component
<section> <section>
<header> <header>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> <h2 class="text-lg font-medium text-nexi-black dark:text-gray-100">
{{ __('Update Password') }} {{ __('Update Password') }}
</h2> </h2>

View File

@ -57,7 +57,7 @@ new class extends Component
<section> <section>
<header> <header>
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> <h2 class="text-lg font-medium text-nexi-black dark:text-gray-100">
{{ __('Profile Information') }} {{ __('Profile Information') }}
</h2> </h2>
@ -80,10 +80,10 @@ new class extends Component
@if (auth()->user() instanceof MustVerifyEmail && ! auth()->user()->hasVerifiedEmail()) @if (auth()->user() instanceof MustVerifyEmail && ! auth()->user()->hasVerifiedEmail())
<div> <div>
<p class="text-sm mt-2 text-gray-800 dark:text-gray-200"> <p class="text-sm mt-2 text-nexi-black dark:text-gray-200">
{{ __('Your email address is unverified.') }} {{ __('Your email address is unverified.') }}
<button wire:click.prevent="sendVerification" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"> <button wire:click.prevent="sendVerification" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-nexi-black dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-nexi-black">
{{ __('Click here to re-send the verification email.') }} {{ __('Click here to re-send the verification email.') }}
</button> </button>
</p> </p>

View File

@ -1,25 +1,25 @@
<x-app-layout> <x-app-layout>
<x-slot name="header"> <x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight"> <h2 class="font-semibold text-xl text-nexi-black dark:text-gray-200 leading-tight">
{{ __('Profile') }} {{ __('Profile') }}
</h2> </h2>
</x-slot> </x-slot>
<div class="py-12"> <div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg"> <div class="p-4 sm:p-8 shadow sm:rounded-lg dark:shadow-zinc-600">
<div class="max-w-xl"> <div class="max-w-xl">
<livewire:profile.update-profile-information-form /> <livewire:profile.update-profile-information-form />
</div> </div>
</div> </div>
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg"> <div class="p-4 sm:p-8 shadow sm:rounded-lg dark:shadow-zinc-600">
<div class="max-w-xl"> <div class="max-w-xl">
<livewire:profile.update-password-form /> <livewire:profile.update-password-form />
</div> </div>
</div> </div>
<div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg"> <div class="p-4 sm:p-8 shadow sm:rounded-lg dark:shadow-zinc-600">
<div class="max-w-xl"> <div class="max-w-xl">
<livewire:profile.delete-user-form /> <livewire:profile.delete-user-form />
</div> </div>

View File

@ -39,6 +39,7 @@ export default {
'nexi-red': "rgb( 235, 49, 46)", 'nexi-red': "rgb( 235, 49, 46)",
'nexi-grey': "rgb(228, 228, 228)", 'nexi-grey': "rgb(228, 228, 228)",
'nexi-darker-grey': "rgb(210, 210, 210)", 'nexi-darker-grey': "rgb(210, 210, 210)",
'nexi-dark-grey': "rgb(98,98,98)",
'nexi-green': "rgb(54, 234, 123)", 'nexi-green': "rgb(54, 234, 123)",
'nexi-cyan': "rgb(54, 233, 234)", 'nexi-cyan': "rgb(54, 233, 234)",
'nexi-purple': "rgb(166, 37, 234)", 'nexi-purple': "rgb(166, 37, 234)",

View File

@ -1,53 +0,0 @@
<?php
use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Verified;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\URL;
test('email verification screen can be rendered', function () {
$user = User::factory()->create([
'email_verified_at' => null,
]);
$response = $this->actingAs($user)->get('/verify-email');
$response->assertStatus(200);
});
test('email can be verified', function () {
$user = User::factory()->create([
'email_verified_at' => null,
]);
Event::fake();
$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1($user->email)]
);
$response = $this->actingAs($user)->get($verificationUrl);
Event::assertDispatched(Verified::class);
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
$response->assertRedirect(RouteServiceProvider::HOME.'?verified=1');
});
test('email is not verified with invalid hash', function () {
$user = User::factory()->create([
'email_verified_at' => null,
]);
$verificationUrl = URL::temporarySignedRoute(
'verification.verify',
now()->addMinutes(60),
['id' => $user->id, 'hash' => sha1('wrong-email')]
);
$this->actingAs($user)->get($verificationUrl);
expect($user->fresh()->hasVerifiedEmail())->toBeFalse();
});