Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,48 @@
|
||||
@php
|
||||
\Log::info('REMINDER: component rendering started');
|
||||
|
||||
$hasMultipleProfiles = userHasMultipleProfiles();
|
||||
\Log::info('REMINDER: userHasMultipleProfiles', ['result' => $hasMultipleProfiles]);
|
||||
|
||||
$activeProfileName = session('activeProfileName');
|
||||
$activeProfilePhoto = session('activeProfilePhoto');
|
||||
$activeProfileRoleLabel = session('activeProfileRoleLabel');
|
||||
|
||||
\Log::info('REMINDER: session data', [
|
||||
'hasMultiple' => $hasMultipleProfiles,
|
||||
'name' => $activeProfileName,
|
||||
'photo' => $activeProfilePhoto,
|
||||
'role' => $activeProfileRoleLabel,
|
||||
]);
|
||||
@endphp
|
||||
|
||||
@if($hasMultipleProfiles && $activeProfileName)
|
||||
@php
|
||||
$photoUrl = $activeProfilePhoto ? \Illuminate\Support\Facades\Storage::url($activeProfilePhoto) : null;
|
||||
$translatedRole = $activeProfileRoleLabel ? __($activeProfileRoleLabel) : null;
|
||||
\Log::info('REMINDER: rendering banner', ['name' => $activeProfileName, 'role' => $translatedRole]);
|
||||
@endphp
|
||||
<div class="bg-theme-surface border-b border-theme-border py-3 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto flex items-center gap-3">
|
||||
@if($photoUrl)
|
||||
<img src="{{ $photoUrl }}" alt="{{ $activeProfileName }}" class="w-8 h-8 rounded-full object-cover flex-shrink-0">
|
||||
@endif
|
||||
<div class="flex-1">
|
||||
<div class="text-sm text-theme-muted">{{ __('Active profile') }}</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-semibold text-theme-primary text-sm">{{ $activeProfileName }}</span>
|
||||
@if($translatedRole)
|
||||
<span class="text-xs text-theme-secondary bg-theme-background px-2 py-1 rounded">{{ $translatedRole }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@php
|
||||
\Log::info('REMINDER: not rendering - no multiple profiles or no name', [
|
||||
'hasMultiple' => $hasMultipleProfiles,
|
||||
'hasName' => !empty($activeProfileName),
|
||||
]);
|
||||
@endphp
|
||||
@endif
|
||||
@@ -0,0 +1,119 @@
|
||||
@props([
|
||||
'result' => [],
|
||||
'index' => 0,
|
||||
'href' => null,
|
||||
'wireClick' => null,
|
||||
'showScore' => false,
|
||||
'showCallable' => true,
|
||||
'showReactions' => true,
|
||||
'photoBlur' => 0,
|
||||
'photoContrast' => 100,
|
||||
'photoSaturate' => 100,
|
||||
'photoBrightness' => 100,
|
||||
'heightClass' => 'h-[430px] md:h-[550px] lg:h-[430px]',
|
||||
'truncateExcerpt' => false,
|
||||
])
|
||||
|
||||
<div class="relative flex flex-col justify-end overflow-hidden rounded-lg bg-theme-background shadow-2xl {{ $heightClass }}">
|
||||
@if ($wireClick)
|
||||
<a href="#" wire:click.prevent="{{ $wireClick }}"
|
||||
class="relative flex h-full cursor-pointer flex-col overflow-hidden rounded-lg">
|
||||
@else
|
||||
<a href="{{ $href ?? route('call.show', ['id' => $result['id']]) }}"
|
||||
class="relative flex h-full cursor-pointer flex-col overflow-hidden rounded-lg">
|
||||
@endif
|
||||
|
||||
<!-- Tag category color background -->
|
||||
<div class="absolute inset-0 z-0 bg-{{ $result['tag_color'] ?? 'gray' }}-400"></div>
|
||||
<div class="absolute inset-0 z-10 bg-black/50"></div>
|
||||
|
||||
<!-- Card content -->
|
||||
<div class="relative z-20 flex h-full flex-col justify-between px-6 pt-10 pb-10 lg:px-14 lg:pt-14 lg:pb-14 text-white">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
{{-- Deepest tag category badge only --}}
|
||||
@php $deepestCat = !empty($result['tag_categories']) ? last($result['tag_categories']) : null; @endphp
|
||||
@if ($deepestCat)
|
||||
<span onclick="event.preventDefault(); event.stopPropagation(); window.location='{{ route('search.show') }}?category={{ $deepestCat['id'] ?? '' }}'"
|
||||
class="bg-{{ $deepestCat['color'] ?? 'gray' }}-400 inline-flex cursor-pointer items-center rounded-md px-2 py-1 text-sm font-normal text-black hover:opacity-80">
|
||||
{{ $deepestCat['name'] }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
{{-- Reaction button --}}
|
||||
@if ($showReactions)
|
||||
<div class="flex items-start -m-2 flex-shrink-0">
|
||||
<div class="-my-3">
|
||||
@livewire('reaction-button', [
|
||||
'typeName' => 'like',
|
||||
'showCounter' => true,
|
||||
'reactionCounter' => $result['like_count'],
|
||||
'modelClass' => $result['model'],
|
||||
'modelId' => $result['id'],
|
||||
'size' => 'w-6 h-6',
|
||||
'inverseColors' => true,
|
||||
], key('like-' . $result['model'] . '-' . $result['id'] . '-' . $index))
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="my-3 text-4xl font-semibold leading-tight line-clamp-2">
|
||||
{{ $result['title'] }}
|
||||
</h2>
|
||||
{{-- Location + expiry badges --}}
|
||||
@if (!empty($result['location']) || !empty($result['expiry_badge_text']))
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
@if (!empty($result['location']))
|
||||
<h4 class="inline-block items-center rounded-sm bg-black px-2 pb-1 pt-0.5 text-sm font-normal uppercase text-white">
|
||||
{{ $result['location'] }}
|
||||
</h4>
|
||||
@endif
|
||||
@if (!empty($result['expiry_badge_text']))
|
||||
<h4 class="inline-block items-center rounded-sm bg-black px-2 pb-1 pt-0.5 text-sm font-normal uppercase text-white">
|
||||
{{ $result['expiry_badge_text'] }}
|
||||
</h4>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<p class="mt-3 text-base font-semibold {{ $truncateExcerpt ? 'line-clamp-2' : '' }}">
|
||||
{{ $result['excerpt'] }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($showCallable)
|
||||
<div class="flex flex-wrap items-end gap-4">
|
||||
<div class="flex items-center gap-3">
|
||||
{{-- Callable avatar --}}
|
||||
@if (!empty($result['photo']))
|
||||
<div class="h-16 w-16 flex-shrink-0 rounded-full outline outline-1 outline-offset-1 outline-white/50 overflow-hidden">
|
||||
<img src="{{ $result['photo'] }}"
|
||||
alt="{{ $result['callable_name'] }}"
|
||||
class="h-full w-full object-cover" />
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex flex-col gap-1 text-sm">
|
||||
{{-- Callable name --}}
|
||||
@if (!empty($result['callable_name']))
|
||||
<span class="font-medium">{{ $result['callable_name'] }}</span>
|
||||
@endif
|
||||
{{-- Callable location --}}
|
||||
@if (!empty($result['callable_location']))
|
||||
<span class="text-white/80">{{ $result['callable_location'] }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($showScore)
|
||||
<div class="text-2xs absolute bottom-5 right-5 z-20 text-transparent sm:text-white drop-shadow">
|
||||
{{ __('search score') . ': ' . round($result['score'] ?? 0, 1) }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,67 @@
|
||||
<footer class="bg-theme-brand mx-auto pt-4 lg:pt-9">
|
||||
|
||||
<div class="container mx-auto max-w-7xl px-6 py-9 sm:px-6 lg:px-8">
|
||||
<div class="grid grid-cols-2 gap-y-12 gap-x-8 md:gap-12 text-base md:grid-cols-3 lg:grid-cols-4">
|
||||
|
||||
@php
|
||||
$footerSections = collect(timebank_config('footer.sections', []))
|
||||
->where('visible', true)
|
||||
->sortBy('order');
|
||||
@endphp
|
||||
|
||||
@foreach($footerSections as $section)
|
||||
<div>
|
||||
<p class="text-sm font-extrabold text-theme-background md:font-semibold dark:text-theme-background">
|
||||
{{ __($section['title']) }}
|
||||
</p>
|
||||
|
||||
<div class="mt-1 flex flex-col items-start space-y-2 text-xs">
|
||||
@php
|
||||
// A link to a route this platform does not register (e.g. a disabled local page) is left out
|
||||
$links = collect($section['links'] ?? [])
|
||||
->where('visible', true)
|
||||
->filter(fn ($link) => isset($link['url']) || \Illuminate\Support\Facades\Route::has($link['route'] ?? ''))
|
||||
->sortBy('order');
|
||||
@endphp
|
||||
|
||||
@foreach($links as $link)
|
||||
@if(isset($link['auth_required']) && $link['auth_required'])
|
||||
@auth
|
||||
<a class="text-theme-light hover:text-theme-accent dark:text-theme-secondary dark:hover:text-theme-accent transition-colors duration-300 hover:underline"
|
||||
href="{{ route($link['route']) }}">
|
||||
{{ __($link['title']) }}
|
||||
</a>
|
||||
@endauth
|
||||
@elseif(isset($link['url']))
|
||||
<a class="text-theme-light hover:text-theme-accent dark:text-theme-secondary dark:hover:text-theme-accent transition-colors duration-300 hover:underline"
|
||||
href="{{ $link['url'] }}">
|
||||
{{ __($link['title']) }}
|
||||
</a>
|
||||
@else
|
||||
<a class="text-theme-light hover:text-theme-accent dark:text-theme-secondary dark:hover:text-theme-accent transition-colors duration-300 hover:underline"
|
||||
href="{{ route($link['route']) }}">
|
||||
{{ __($link['title']) }}
|
||||
</a>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Bottom Section: Application Mark and Text -->
|
||||
<div class="my-6 flex w-full flex-col items-end justify-end space-y-2">
|
||||
<div class="invert-100 flex flex-col items-center justify-center">
|
||||
<a href="{{ route('main') }}">
|
||||
<x-jetstream.application-mark class="block h-9 w-auto" style="max-width: 80px;" />
|
||||
</a>
|
||||
|
||||
<p class="mt-2 text-2xs dark:text-theme-light font-semibold text-gray-800">
|
||||
{{ __(timebank_config('footer.tagline','')) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,6 @@
|
||||
<button {{ $attributes->merge([
|
||||
'type' => 'button',
|
||||
'class' => 'inline-flex items-center pl-4 pr-2 py-2 bg-theme-background border border-theme-border rounded-md font-semibold text-xs text-theme-primary uppercase tracking-widest shadow-sm hover:bg-theme-border hover:text-theme-secondary focus:outline-none focus:border-blue-300 focus:ring focus:ring-blue-200 active:text-theme-primary active:bg-theme-surface disabled:opacity-25 transition']) }}>
|
||||
{{ $slot }}
|
||||
<span class="ml-2"><x-icon name="chevron-down" class="w-5 h-5" mini/></span>
|
||||
</button>
|
||||
@@ -0,0 +1,10 @@
|
||||
@props(['on'])
|
||||
|
||||
<div x-data="{ shown: false, timeout: null }"
|
||||
x-init="@this.on('{{ $on }}', () => { clearTimeout(timeout); shown = true; timeout = setTimeout(() => { shown = false }, 2000); })"
|
||||
x-show.transition.out.opacity.duration.1500ms="shown"
|
||||
x-transition:leave.opacity.duration.1500ms
|
||||
style="display: none;"
|
||||
{{ $attributes->merge(['class' => 'text-sm text-theme-secondary']) }}>
|
||||
{!! $slot->isEmpty() ? 'Saved.' : $slot !!}
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<div {{ $attributes->merge(['class' => 'md:grid md:grid-cols-3 md:gap-6']) }}>
|
||||
<x-jetstream.section-title>
|
||||
<x-slot name="title">{{ $title }}</x-slot>
|
||||
<x-slot name="description">{{ $description }}</x-slot>
|
||||
</x-jetstream.section-title>
|
||||
|
||||
<div class="md:mt-0 md:col-span-2">
|
||||
<div class="px-4 py-5 sm:p-6 bg-theme-background shadow sm:rounded-lg">
|
||||
{{ $content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="w-full max-w-md mx-auto">
|
||||
@include(theme_logo('svg_inline', 'logos.timebank_cc'), ['logoTitle' => $logoTitle ?? __('Search') . ' - ' . config('app.name')])
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<div {{ $attributes }}>
|
||||
@include(theme_logo('svg_inline', 'logos.timebank_cc'), ['logoTitle' => $logoTitle ?? config('app.name')])
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<a href="/" class="block max-w-md">
|
||||
<div class="w-full h-auto">
|
||||
@include(theme_logo('svg_inline', 'logos.timebank_cc'), ['logoTitle' => $logoTitle ?? __('Go to homepage') . ' - ' . config('app.name')])
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="min-h-screen flex flex-col justify-center items-center py-6 relative overflow-hidden">
|
||||
<!-- Background Image -->
|
||||
<div class="absolute inset-0 z-0">
|
||||
@livewire('welcome.login-landing-post', ['type' => 'SiteContents\Welcome\Landing' ?? null, 'random' => true, 'limit' => 1])
|
||||
</div>
|
||||
|
||||
<!-- Login Modal Card -->
|
||||
<div class="mx-8 sm:max-w-md px-12 py-6 bg-theme-background dark:bg-theme-secondary backdrop-blur-sm shadow-2xl rounded-lg z-20 relative">
|
||||
<div class="flex justify-center mb-8">
|
||||
{{ $logo }}
|
||||
</div>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
@props(['style' => session('flash.bannerStyle', 'success'), 'message' => session('flash.banner')])
|
||||
|
||||
<div x-data="{{ json_encode(['show' => true, 'style' => $style, 'message' => $message]) }}"
|
||||
:class="{ 'bg-green-100': style == 'success', 'bg-red-100': style == 'danger', 'bg-theme-surface': style != 'success' && style != 'danger' }"
|
||||
style="display: none;"
|
||||
x-show="show && message"
|
||||
x-init="
|
||||
document.addEventListener('banner-message', event => {
|
||||
style = event.detail.style;
|
||||
message = event.detail.message;
|
||||
show = true;
|
||||
});
|
||||
">
|
||||
<div class="mx-auto py-2 px-3 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between flex-wrap">
|
||||
<div class="w-0 flex-1 flex items-center min-w-0">
|
||||
<span class="flex p-2 rounded-lg" :class="{ 'bg-green-100': style == 'success', 'bg-red-100': style == 'danger' }">
|
||||
<svg x-show="style == 'success'" class="h-5 w-5 text-green-700" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<svg x-show="style == 'danger'" class="h-5 w-5 text-red-700" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<svg x-show="style != 'success' && style != 'danger'" class="h-5 w-5 text-dark" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<p class="ml-3 font-medium text-sm text-dark truncate" x-text="message"></p>
|
||||
</div>
|
||||
|
||||
<div class="shrink-0 sm:ml-3">
|
||||
<button
|
||||
type="button"
|
||||
class="-mr-1 flex p-2 rounded-md focus:outline-none sm:-mr-2 transition"
|
||||
:class="{ 'hover:bg-green-300 focus:bg-green-300': style == 'success', 'hover:bg-red-300 focus:bg-red-300': style == 'danger' }"
|
||||
aria-label="Dismiss"
|
||||
x-on:click="show = false">
|
||||
<svg class="h-5 w-5 text-dark" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
@php
|
||||
// Determine the wire target from wire:click or use explicit wire:target if provided
|
||||
$wireTarget = null;
|
||||
|
||||
if ($attributes->has('wire:target')) {
|
||||
$wireTarget = $attributes->get('wire:target');
|
||||
} else {
|
||||
// Look for wire:click variants (wire:click, wire:click.prevent, etc.)
|
||||
foreach ($attributes->getAttributes() as $key => $value) {
|
||||
if (str_starts_with($key, 'wire:click')) {
|
||||
// Skip $dispatch, $set, $toggle etc. as they don't create loading states
|
||||
if (!str_starts_with(trim($value), '$')) {
|
||||
$wireTarget = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
|
||||
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center justify-center px-4 py-2 bg-theme-primary-900 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest shadow-lg hover:shadow-sm hover:bg-theme-primary-700 hover:text-theme-primary-100 focus:outline-none focus:border-theme-accent focus:ring-1 focus:ring-theme-accent active:bg-theme-primary-900 disabled:opacity-25 transition']) }}>
|
||||
@if(!$attributes->has('no-spinner') && $wireTarget)
|
||||
<span class="relative flex items-center justify-center w-full">
|
||||
<span wire:loading wire:target="{{ $wireTarget }}" class="absolute flex items-center justify-center">
|
||||
<svg class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span wire:loading.class="opacity-0" wire:target="{{ $wireTarget }}" class="inline-flex items-center">
|
||||
{{ $slot }}
|
||||
</span>
|
||||
</span>
|
||||
@else
|
||||
{{ $slot }}
|
||||
@endif
|
||||
</button>
|
||||
@@ -0,0 +1 @@
|
||||
<input type="checkbox" {!! $attributes->merge(['class' => 'rounded border-theme-border text-theme-secondary shadow-sm focus:border-theme-border focus:ring focus:ring-gray-200 focus:ring-opacity-50']) !!}>
|
||||
@@ -0,0 +1,27 @@
|
||||
@props(['id' => null, 'maxWidth' => null])
|
||||
|
||||
<x-jetstream.modal :id="$id" :maxWidth="$maxWidth" {{ $attributes }}>
|
||||
<div class="bg-theme-background px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div class="mx-auto shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<svg class="h-6 w-6 text-red-600" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg">
|
||||
{!! $title !!}
|
||||
</h3>
|
||||
|
||||
<div class="mt-2">
|
||||
{!! $content !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row justify-end px-6 py-4 bg-theme-surface text-right">
|
||||
{!! $footer !!}
|
||||
</div>
|
||||
</x-jetstream.modal>
|
||||
@@ -0,0 +1,46 @@
|
||||
@props(['title' => __('Confirm Password'), 'content' => __('For your security, please confirm your password to continue.'), 'button' => __('Confirm')])
|
||||
|
||||
@php
|
||||
$confirmableId = md5($attributes->wire('then'));
|
||||
@endphp
|
||||
|
||||
<span
|
||||
{{ $attributes->wire('then') }}
|
||||
x-data
|
||||
x-ref="span"
|
||||
x-on:click="$wire.startConfirmingPassword('{{ $confirmableId }}')"
|
||||
x-on:password-confirmed.window="setTimeout(() => $event.detail.id === '{{ $confirmableId }}' && $refs.span.dispatchEvent(new CustomEvent('then', { bubbles: false })), 250);"
|
||||
>
|
||||
{{ $slot }}
|
||||
</span>
|
||||
|
||||
@once
|
||||
<x-jetstream.dialog-modal wire:model.live="confirmingPassword">
|
||||
<x-slot name="title">
|
||||
{{ $title }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
{{ $content }}
|
||||
|
||||
<div class="mt-4" x-data="{}" x-on:confirming-password.window="setTimeout(() => $refs.confirmable_password.focus(), 250)">
|
||||
<x-jetstream.input type="password" class="mt-1 block w-3/4" placeholder="{{ __('Password') }}"
|
||||
x-ref="confirmable_password"
|
||||
wire:model="confirmablePassword"
|
||||
wire:keydown.enter="confirmPassword" />
|
||||
|
||||
<x-jetstream.input-error for="confirmable_password" class="mt-2" />
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="footer">
|
||||
<x-jetstream.secondary-button wire:click="stopConfirmingPassword" wire:loading.attr="disabled">
|
||||
{{ __('Cancel') }}
|
||||
</x-jetstream.secondary-button>
|
||||
|
||||
<x-jetstream.button class="ml-3" dusk="confirm-password-button" wire:click="confirmPassword" wire:loading.attr="disabled">
|
||||
{{ $button }}
|
||||
</x-jetstream.button>
|
||||
</x-slot>
|
||||
</x-jetstream.dialog-modal>
|
||||
@endonce
|
||||
@@ -0,0 +1,37 @@
|
||||
@php
|
||||
// Determine the wire target from wire:click or use explicit wire:target if provided
|
||||
$wireTarget = null;
|
||||
|
||||
if ($attributes->has('wire:target')) {
|
||||
$wireTarget = $attributes->get('wire:target');
|
||||
} else {
|
||||
// Look for wire:click variants (wire:click, wire:click.prevent, etc.)
|
||||
foreach ($attributes->getAttributes() as $key => $value) {
|
||||
if (str_starts_with($key, 'wire:click')) {
|
||||
// Skip $dispatch, $set, $toggle etc. as they don't create loading states
|
||||
if (!str_starts_with(trim($value), '$')) {
|
||||
$wireTarget = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
|
||||
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center justify-center px-4 py-2 bg-theme-danger-dark border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest shadow-md hover:shadow-sm hover:bg-theme-danger focus:outline-none focus:border-theme-accent focus:ring-1 focus:ring-theme-accent active:bg-theme-danger disabled:opacity-25 transition']) }}>
|
||||
@if(!$attributes->has('no-spinner') && $wireTarget)
|
||||
<span class="relative flex items-center justify-center w-full">
|
||||
<span wire:loading wire:target="{{ $wireTarget }}" class="absolute flex items-center justify-center">
|
||||
<svg class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span wire:loading.class="opacity-0" wire:target="{{ $wireTarget }}" class="inline-flex items-center">
|
||||
{{ $slot }}
|
||||
</span>
|
||||
</span>
|
||||
@else
|
||||
{{ $slot }}
|
||||
@endif
|
||||
</button>
|
||||
@@ -0,0 +1,24 @@
|
||||
@props(['id' => null, 'maxWidth' => null, 'closeButton' => false])
|
||||
|
||||
<x-jetstream.modal :id="$id" :maxWidth="$maxWidth" {{ $attributes }}>
|
||||
<div class="px-6 py-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-xl font-medium">
|
||||
{!! $title !!}
|
||||
</div>
|
||||
@if($closeButton)
|
||||
<button type="button" @click="show = false" class="hover:text-theme-secondary transition-colors">
|
||||
<x-icon name="x-mark" class="w-6 h-6" />
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="m-6">
|
||||
{!! $content !!}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row justify-end px-6 py-6 text-right">
|
||||
{!! $footer !!}
|
||||
</div>
|
||||
</div>
|
||||
</x-jetstream.modal>
|
||||
@@ -0,0 +1 @@
|
||||
<a {{ $attributes->merge(['class' => 'block px-4 py-2 text-sm leading-5 text-theme-primary hover:bg-theme-surface focus:outline-none focus:bg-theme-surface transition']) }}>{{ $slot }}</a>
|
||||
@@ -0,0 +1,47 @@
|
||||
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-theme-background', 'dropdownClasses' => ''])
|
||||
|
||||
@php
|
||||
switch ($align) {
|
||||
case 'left':
|
||||
$alignmentClasses = 'origin-top-left left-0';
|
||||
break;
|
||||
case 'top':
|
||||
$alignmentClasses = 'origin-top';
|
||||
break;
|
||||
case 'none':
|
||||
case 'false':
|
||||
$alignmentClasses = '';
|
||||
break;
|
||||
case 'right':
|
||||
default:
|
||||
$alignmentClasses = 'origin-top-right right-0';
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($width) {
|
||||
case '48':
|
||||
$width = 'w-48';
|
||||
break;
|
||||
}
|
||||
@endphp
|
||||
|
||||
<div class="relative" x-data="{ open: false }" @click.away="open = false" @close.stop="open = false">
|
||||
<div @click="open = ! open">
|
||||
{{ $trigger }}
|
||||
</div>
|
||||
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
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"
|
||||
x-transition:leave-start="transform opacity-100 scale-100"
|
||||
x-transition:leave-end="transform opacity-0 scale-95"
|
||||
class="absolute z-50 mt-2 {{ $width }} max-w-[calc(100vw-1rem)] rounded-md shadow-lg {{ $alignmentClasses }} {{ $dropdownClasses }}"
|
||||
style="display: none;"
|
||||
@click="open = false">
|
||||
<div class="rounded-md ring-1 ring-black ring-opacity-5 {{ $contentClasses }}">
|
||||
{{ $content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
@props(['submit'])
|
||||
|
||||
<div {{ $attributes->merge(['class' => 'md:grid md:grid-cols-3 md:gap-6']) }}>
|
||||
<div class="mt-6 mb-6 md:mt-0 md:mb-0">
|
||||
<x-jetstream.section-title>
|
||||
<x-slot name="title">{{ $title }}</x-slot>
|
||||
<x-slot name="description">{{ $description }}</x-slot>
|
||||
</x-jetstream.section-title>
|
||||
</div>
|
||||
|
||||
<div class="md:mt-0 md:col-span-2">
|
||||
<form wire:submit="{{ $submit }}">
|
||||
<div class="px-4 py-5 bg-theme-background sm:p-6 shadow sm:rounded-md">
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
{{ $form }}
|
||||
</div>
|
||||
@if (isset($actions))
|
||||
<div class="flex items-center justify-end px-4 py-3 bg-gray-white text-right">
|
||||
{{ $actions }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
@props(['for'])
|
||||
|
||||
@error($for)
|
||||
<p {{ $attributes->merge(['class' => 'text-sm text-red-600']) }}>{{ $message }}</p>
|
||||
@enderror
|
||||
@@ -0,0 +1,3 @@
|
||||
@props(['disabled' => false])
|
||||
|
||||
<input {{ $disabled ? 'disabled' : '' }} {!! $attributes->merge(['class' => 'border-theme-border focus:border-theme-accent focus:ring-1 focus:ring-theme-accent rounded-md shadow-sm']) !!}>
|
||||
@@ -0,0 +1,5 @@
|
||||
@props(['value'])
|
||||
|
||||
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-theme-primary']) }}>
|
||||
{!! html_entity_decode($value ?? $slot, ENT_QUOTES | ENT_HTML5, 'UTF-8') !!}
|
||||
</label>
|
||||
@@ -0,0 +1,7 @@
|
||||
<button {{ $attributes->merge([
|
||||
'type' => 'button',
|
||||
'class' => 'inline-flex items-center px-4 py-2 bg-theme-surface border border-theme-border rounded-md font-semibold text-xs text-theme-primary uppercase tracking-widest shadow-md hover:shadow-sm hover:bg-theme-primary-50 hover:text-theme-secondary focus:outline-none focus:border-theme-accent focus:ring-1 focus:ring-theme-accent active:text-theme-primary active:bg-theme-surface disabled:opacity-25 transition']) }}>
|
||||
{{ $slot }}
|
||||
</button>
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
@props(['id', 'maxWidth'])
|
||||
|
||||
@php
|
||||
$id = $id ?? md5($attributes->wire('model'));
|
||||
|
||||
$maxWidth = [
|
||||
'sm' => 'sm:max-w-sm',
|
||||
'md' => 'sm:max-w-md',
|
||||
'lg' => 'sm:max-w-lg',
|
||||
'xl' => 'sm:max-w-xl',
|
||||
'2xl' => 'sm:max-w-2xl',
|
||||
'3xl' => 'sm:max-w-3xl',
|
||||
'4xl' => 'sm:max-w-4xl',
|
||||
][$maxWidth ?? '2xl'];
|
||||
@endphp
|
||||
|
||||
<div
|
||||
x-data="{
|
||||
show: @entangle($attributes->wire('model')),
|
||||
focusables() {
|
||||
// All focusable element types...
|
||||
let selector = 'a, button, input:not([type=\'hidden\']), textarea, select, details, [tabindex]:not([tabindex=\'-1\'])'
|
||||
|
||||
return [...$el.querySelectorAll(selector)]
|
||||
// All non-disabled elements...
|
||||
.filter(el => ! el.hasAttribute('disabled'))
|
||||
},
|
||||
firstFocusable() { return this.focusables()[0] },
|
||||
lastFocusable() { return this.focusables().slice(-1)[0] },
|
||||
nextFocusable() { return this.focusables()[this.nextFocusableIndex()] || this.firstFocusable() },
|
||||
prevFocusable() { return this.focusables()[this.prevFocusableIndex()] || this.lastFocusable() },
|
||||
nextFocusableIndex() { return (this.focusables().indexOf(document.activeElement) + 1) % (this.focusables().length + 1) },
|
||||
prevFocusableIndex() { return Math.max(0, this.focusables().indexOf(document.activeElement)) -1 },
|
||||
}"
|
||||
|
||||
x-init="$watch('show', value => {
|
||||
if (value) {
|
||||
document.body.classList.add('overflow-y-hidden');
|
||||
{{ $attributes->has('focusable') ? 'setTimeout(() => firstFocusable().focus(), 100)' : '' }}
|
||||
} else {
|
||||
document.body.classList.remove('overflow-y-hidden');
|
||||
@this.dispatch('closeModal');
|
||||
}
|
||||
})"
|
||||
x-on:close.stop="show = false"
|
||||
x-on:keydown.escape.window="show = false"
|
||||
x-on:keydown.tab.prevent="$event.shiftKey || nextFocusable().focus()"
|
||||
x-on:keydown.shift.tab.prevent="prevFocusable().focus()"
|
||||
x-show="show"
|
||||
id="{{ $id }}"
|
||||
class="jetstream-modal fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-[90]"
|
||||
style="display: none;"
|
||||
>
|
||||
<div x-show="show" class="fixed inset-0 transform transition-all" {{--x-on:click="show = false"--}} x-transition:enter="ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
>
|
||||
<div class="absolute inset-0 bg-black opacity-50"></div>
|
||||
</div>
|
||||
|
||||
<div x-show="show" class="mb-6 bg-theme-background 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-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:leave="ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
@props(['active'])
|
||||
|
||||
@php
|
||||
$classes = ($active ?? false)
|
||||
? 'inline-flex items-center px-1 pt-1 border-theme-muted text-xs md:text-sm font-medium leading-5 text-theme-primary hover:text-theme-secondary focus:outline-none focus:border-gray-900 whitespace-nowrap'
|
||||
: 'inline-flex items-center px-1 pt-1 border-transparent text-xs md:text-sm font-medium leading-5 text-theme-primary hover:text-theme-secondary hover:border-theme-border focus:outline-none focus:text-theme-primary focus:border-theme-border transition whitespace-nowrap';
|
||||
@endphp
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
{{ $slot }}
|
||||
</a>
|
||||
@@ -0,0 +1,11 @@
|
||||
@props(['active'])
|
||||
|
||||
@php
|
||||
$classes = ($active ?? false)
|
||||
? 'block pl-3 pr-4 py-2 border-l-4 border-black text-base font-semibold text-theme-primary bg-theme-surface focus:outline-none focus:text-theme-secondary focus:bg-theme-border focus:border-gray-700'
|
||||
: 'block pl-3 pr-4 py-2 border-l-4 border-transparent text-base text-theme-primary leading-5 hover:text-theme-primary hover:bg-theme-surface hover:border-theme-border focus:outline-none focus:text-theme-primary focus:bg-theme-surface focus:border-theme-border';
|
||||
@endphp
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
{{ $slot }}
|
||||
</a>
|
||||
@@ -0,0 +1,41 @@
|
||||
@php
|
||||
// Determine the wire target from wire:click or use explicit wire:target if provided
|
||||
$wireTarget = null;
|
||||
|
||||
if ($attributes->has('wire:target')) {
|
||||
$wireTarget = $attributes->get('wire:target');
|
||||
} else {
|
||||
// Look for wire:click variants (wire:click, wire:click.prevent, etc.)
|
||||
foreach ($attributes->getAttributes() as $key => $value) {
|
||||
if (str_starts_with($key, 'wire:click')) {
|
||||
// Skip $dispatch, $set, $toggle etc. as they don't create loading states
|
||||
if (!str_starts_with(trim($value), '$')) {
|
||||
$wireTarget = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
|
||||
<button {{ $attributes->merge([
|
||||
'type' => 'button',
|
||||
'class' => 'inline-flex items-center px-4 py-2 bg-theme-button-secondary border border-theme-border rounded-md font-semibold text-xs text-theme-button-secondary-text uppercase tracking-widest shadow-md hover:shadow-sm hover:bg-theme-border hover:text-theme-secondary focus:outline-none focus:border-theme-accent focus:ring-1 focus:ring-theme-accent active:text-theme-primary active:bg-theme-surface disabled:opacity-25 transition']) }}>
|
||||
@if(!$attributes->has('no-spinner') && $wireTarget)
|
||||
<span class="relative flex items-center justify-center w-full">
|
||||
<span wire:loading wire:target="{{ $wireTarget }}" class="absolute flex items-center justify-center">
|
||||
<svg class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span wire:loading.class="opacity-0" wire:target="{{ $wireTarget }}" class="inline-flex items-center">
|
||||
{{ $slot }}
|
||||
</span>
|
||||
</span>
|
||||
@else
|
||||
{{ $slot }}
|
||||
@endif
|
||||
</button>
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="hidden sm:block">
|
||||
<div class="py-8">
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="md:col-span-1 flex justify-between">
|
||||
<div class="px-4 sm:px-0">
|
||||
<h3 class="text-xl font-strong text-theme-primary">{!! $title !!}</h3>
|
||||
|
||||
<p class="hidden md:block mt-1 text-sm text-theme-secondary">
|
||||
{!! $description !!}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="px-4 sm:px-0">
|
||||
{!! $aside ?? '' !!}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
@props(['team', 'component' => 'dropdown-link'])
|
||||
|
||||
<form method="POST" action="{{ route('current-team.update') }}" x-data>
|
||||
@method('PUT')
|
||||
@csrf
|
||||
|
||||
<!-- Hidden Team ID -->
|
||||
<input type="hidden" name="team_id" value="{{ $team->id }}">
|
||||
|
||||
<x-dynamic-component :component="$component" href="#" x-on:click.prevent="$root.submit();">
|
||||
<div class="flex items-center">
|
||||
@if (Auth::user()->isCurrentTeam($team))
|
||||
<svg class="mr-2 h-5 w-5 text-green-400" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor" viewBox="0 0 24 24"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
@endif
|
||||
|
||||
<div class="truncate">{{ $team->name }}</div>
|
||||
</div>
|
||||
</x-dynamic-component>
|
||||
</form>
|
||||
@@ -0,0 +1,51 @@
|
||||
@props(['style' => session('flash.bannerStyle', 'success'), 'message' => session('flash.banner')])
|
||||
|
||||
<div x-data="{{ json_encode(['show' => true, 'style' => $style, 'message' => $message]) }}"
|
||||
:class="{ 'fixed bottom-0 left-0 right-0 bg-green-100': style == 'success', 'fixed bottom-0 left-0 right-0 bg-red-100': style == 'danger', 'fixed bottom-0 left-0 right-0 bg-theme-surface': style != 'success' && style != 'danger' }"
|
||||
|
||||
|
||||
|
||||
style="display: none;"
|
||||
x-show="show && message"
|
||||
x-transition:leave.opacity.duration.1000ms
|
||||
x-init="
|
||||
document.addEventListener('toaster-message', event => {
|
||||
style = event.detail.style;
|
||||
message = event.detail.message;
|
||||
show = true;
|
||||
timeout = setTimeout(() => { show = false }, 4000);
|
||||
});
|
||||
">
|
||||
<div class="mx-auto py-4 px-6 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between flex-wrap">
|
||||
<div class="w-0 flex-1 flex items-center min-w-0">
|
||||
<span class="flex p-2 rounded-lg" :class="{ 'bg-green-100': style == 'success', 'bg-red-100': style == 'danger' }">
|
||||
<svg x-show="style == 'success'" class="h-5 w-5 text-green-700" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<svg x-show="style == 'danger'" class="h-5 w-5 text-red-700" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<svg x-show="style != 'success' && style != 'danger'" class="h-5 w-5 text-dark" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<p class="ml-3 font-medium text-sm text-dark truncate" x-text="message"></p>
|
||||
</div>
|
||||
|
||||
<div class="shrink-0 sm:ml-3">
|
||||
<button
|
||||
type="button"
|
||||
class="-mr-1 flex p-2 rounded-md focus:outline-none sm:-mr-2 transition"
|
||||
:class="{ 'hover:bg-green-300 focus:bg-green-300': style == 'success', 'hover:bg-red-300 focus:bg-red-300': style == 'danger' }"
|
||||
aria-label="Dismiss"
|
||||
x-on:click="show = false">
|
||||
<svg class="h-5 w-5 text-dark" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
@if ($errors->any())
|
||||
<div {{ $attributes }}>
|
||||
<div class="font-medium text-red-600">{{ __('Whoops! Something went wrong.') }}</div>
|
||||
|
||||
<ul class="mt-3 list-disc list-inside text-sm text-red-600">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,93 @@
|
||||
<div class="p-6 sm:px-20 bg-theme-background border-b border-theme-border">
|
||||
<div>
|
||||
<x-jetstream.application-logo class="block h-12 w-auto" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{-- {{ __('Last login at')}} {{ $loginAt }} --}}
|
||||
</div>
|
||||
<div class="mt-8 text-2xl">
|
||||
Welcome to your Jetstream application!
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-theme-muted">
|
||||
Laravel Jetstream provides a beautiful, robust starting point for your next Laravel application. Laravel is designed
|
||||
to help you build your application using a development environment that is simple, powerful, and enjoyable. We believe
|
||||
you should love expressing your creativity through programming, so we have spent time carefully crafting the Laravel
|
||||
ecosystem to be a breath of fresh air. We hope you love it.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-theme-border bg-opacity-25 grid grid-cols-1 md:grid-cols-2">
|
||||
<div class="p-6">
|
||||
<div class="flex items-center">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" class="w-8 h-8 text-theme-muted"><path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg>
|
||||
<div class="ml-4 text-lg text-theme-secondary leading-7 font-semibold"><a href="https://laravel.com/docs">Documentation</a></div>
|
||||
</div>
|
||||
|
||||
<div class="ml-12">
|
||||
<div class="mt-2 text-sm text-theme-muted">
|
||||
Laravel has wonderful documentation covering every aspect of the framework. Whether you're new to the framework or have previous experience, we recommend reading all of the documentation from beginning to end.
|
||||
</div>
|
||||
|
||||
<a href="https://laravel.com/docs">
|
||||
<div class="mt-3 flex items-center text-sm font-semibold text-theme-primary">
|
||||
<div>Explore the documentation</div>
|
||||
|
||||
<div class="ml-1 text-theme-muted">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 border-t border-theme-border md:border-t-0 md:border-l">
|
||||
<div class="flex items-center">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" class="w-8 h-8 text-theme-muted"><path d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"></path><path d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
|
||||
<div class="ml-4 text-lg text-theme-secondary leading-7 font-semibold"><a href="https://laracasts.com">Laracasts</a></div>
|
||||
</div>
|
||||
|
||||
<div class="ml-12">
|
||||
<div class="mt-2 text-sm text-theme-muted">
|
||||
Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process.
|
||||
</div>
|
||||
|
||||
<a href="https://laracasts.com">
|
||||
<div class="mt-3 flex items-center text-sm font-semibold text-theme-primary">
|
||||
<div>Start watching Laracasts</div>
|
||||
|
||||
<div class="ml-1 text-theme-muted">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 border-t border-theme-border">
|
||||
<div class="flex items-center">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" class="w-8 h-8 text-theme-muted"><path d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
|
||||
<div class="ml-4 text-lg text-theme-secondary leading-7 font-semibold"><a href="https://tailwindcss.com/">Tailwind</a></div>
|
||||
</div>
|
||||
|
||||
<div class="ml-12">
|
||||
<div class="mt-2 text-sm text-theme-muted">
|
||||
Laravel Jetstream is built with Tailwind, an amazing utility first CSS framework that doesn't get in your way. You'll be amazed how easily you can build and maintain fresh, modern designs with this wonderful framework at your fingertips.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 border-t border-theme-border md:border-l">
|
||||
<div class="flex items-center">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" class="w-8 h-8 text-theme-muted"><path d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path></svg>
|
||||
<div class="ml-4 text-lg text-theme-secondary leading-7 font-semibold">Authentication</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-12">
|
||||
<div class="mt-2 text-sm text-theme-muted">
|
||||
Authentication and registration views are included with Laravel Jetstream, as well as support for user email verification and resetting forgotten passwords. So, you're free to get started what matters most: building your application.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,53 @@
|
||||
{{--
|
||||
Navigation bar dropdown. The panel is teleported to <body> and positioned under the
|
||||
trigger, because the bar's link container clips overflow (overflow-hidden).
|
||||
Expects: $label, $active (bool); the slot holds <x-jetstream.dropdown-link> items.
|
||||
--}}
|
||||
@props(['label', 'active' => false])
|
||||
|
||||
@php
|
||||
$classes = $active
|
||||
? 'inline-flex items-center px-1 pt-1 border-theme-muted text-xs md:text-sm font-medium leading-5 text-theme-primary hover:text-theme-secondary focus:outline-none whitespace-nowrap'
|
||||
: 'inline-flex items-center px-1 pt-1 border-transparent text-xs md:text-sm font-medium leading-5 text-theme-primary hover:text-theme-secondary hover:border-theme-border focus:outline-none focus:text-theme-primary transition whitespace-nowrap';
|
||||
@endphp
|
||||
|
||||
<div x-data="{
|
||||
open: false,
|
||||
top: 0,
|
||||
left: 0,
|
||||
toggle() {
|
||||
const rect = this.$refs.trigger.getBoundingClientRect();
|
||||
this.top = rect.bottom + 8;
|
||||
this.left = Math.min(rect.left, window.innerWidth - 208);
|
||||
this.open = !this.open;
|
||||
},
|
||||
}"
|
||||
@keydown.escape.window="open = false"
|
||||
@resize.window="open = false"
|
||||
class="inline-flex">
|
||||
<button type="button" x-ref="trigger" @click="toggle()" :aria-expanded="open.toString()" aria-haspopup="true"
|
||||
{{ $attributes->merge(['class' => $classes]) }}>
|
||||
{{ $label }}
|
||||
<svg class="ml-1 h-4 w-4 transition-transform" :class="{ 'rotate-180': open }" xmlns="http://www.w3.org/2000/svg" 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>
|
||||
</button>
|
||||
|
||||
<template x-teleport="body">
|
||||
<div x-show="open" x-cloak
|
||||
@click.outside="if (!$refs.trigger.contains($event.target)) open = false"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
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"
|
||||
x-transition:leave-start="transform opacity-100 scale-100"
|
||||
x-transition:leave-end="transform opacity-0 scale-95"
|
||||
:style="`top: ${top}px; left: ${left}px`"
|
||||
class="fixed z-[90] w-48 rounded-md shadow-lg origin-top-left"
|
||||
role="menu">
|
||||
<div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-theme-background">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -0,0 +1,76 @@
|
||||
<nav id="navigation-menu"
|
||||
class="shadow-md border-b border-theme-primary bg-theme-background fixed top-0 left-0 right-0 z-[80] w-full text-left"
|
||||
wire:ignore.self
|
||||
style="margin: 0; padding: 0; left: 0; right: 0;">
|
||||
@if(auth()->guest() || request()->routeIs('goodbye-deleted-user'))
|
||||
<!-- Primary Navigation Menu -->
|
||||
<div class="relative px-4 lg:px-8" style="max-width: 80rem; width: 100%; margin: 0;">
|
||||
<div class="flex h-16 items-center justify-between">
|
||||
<!-- Logo -->
|
||||
<div class="flex shrink-0 items-center">
|
||||
<a href="{{ route('welcome') }}">
|
||||
<x-jetstream.application-mark class="block h-9 w-auto" style="max-width: 80px;" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Language selector and Auth Links -->
|
||||
<div class="flex items-center">
|
||||
@php
|
||||
$languages = Illuminate\Support\Facades\DB::table('languages')->orderBy('lang_code', 'asc')->get();
|
||||
$supportedLocales = LaravelLocalization::getSupportedLocales();
|
||||
uasort($supportedLocales, function ($a, $b) {
|
||||
return strcmp($a['native'], $b['native']);
|
||||
});
|
||||
@endphp
|
||||
|
||||
<!-- Language Dropdown -->
|
||||
<div class="ms-3">
|
||||
<x-jetstream.dropdown align="right" width="48">
|
||||
<x-slot name="trigger">
|
||||
<span class="inline-flex rounded-md">
|
||||
<button type="button" class="inline-flex items-center px-2 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-theme-primary hover:text-theme-secondary focus:outline-none focus:bg-theme-surface active:bg-theme-surface transition ease-in-out duration-150">
|
||||
<x-icon name="globe-alt" class="w-5 h-4" outline />
|
||||
</button>
|
||||
</span>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="w-60">
|
||||
@foreach ($supportedLocales as $localeCode => $properties)
|
||||
@php
|
||||
$language = $languages->firstWhere('lang_code', strtolower($localeCode));
|
||||
@endphp
|
||||
@if ($language)
|
||||
<div class="block px-4 py-2">
|
||||
<a class="text-theme-primary transition hover:text-theme-secondary focus:border-theme-primary focus:text-theme-secondary"
|
||||
href="{{ LaravelLocalization::getLocalizedURL($localeCode, null, [], true) }}"
|
||||
hreflang="{{ $localeCode }}" rel="alternate">
|
||||
{{ $language->flag }}
|
||||
<span class="ml-3 text-theme-primary">{{ Lang::get($language->name, [], $localeCode) }}</span>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-jetstream.dropdown>
|
||||
</div>
|
||||
|
||||
<!-- Auth Links -->
|
||||
@if (Route::has('login'))
|
||||
<div class="ms-2 flex items-center space-x-3">
|
||||
@if (Route::has('register'))
|
||||
<a href="{{ route('register') }}" class="text-theme-primary hover:text-theme-secondary text-sm font-medium focus:outline-none">
|
||||
{{ __('Register') }}
|
||||
</a>
|
||||
@endif
|
||||
<a href="{{ route('login') }}" class="text-theme-primary hover:text-theme-secondary text-sm font-medium focus:outline-none">
|
||||
{{ __('Log in') }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</nav>
|
||||
@@ -0,0 +1,15 @@
|
||||
<x-jetstream.form-section submit="saveTags">
|
||||
<x-slot name="title">
|
||||
{{ str_replace('@PLATFORM_NAME@', platform_name(), __('Activies you share on @PLATFORM_NAME@')) }}
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="description">
|
||||
<p>{{ trans_with_platform('Which activities and skills can you share on @PLATFORM_NAME_SHORT@? Give practical examples, avoid vague or general keywords.') }}
|
||||
<p> {{ __('Rare skills can be interesting for others, but very common activities are also very useful to offer!') }} </p>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="form">
|
||||
</div>
|
||||
@livewire('skills-form')
|
||||
</x-slot>
|
||||
</x-jetstream.form-section>
|
||||
@@ -0,0 +1,6 @@
|
||||
<x-alert padding="none" title="{{ __('Please add new tags responsibly!') }}" warning>
|
||||
<x-slot name="slot">
|
||||
{{ __('Your name will be linked to this tag keyword.') }} <br>
|
||||
{{ __('New activity tags are reviewed, and inappropriate or useless labels can be removed without notice.') }}
|
||||
</x-slot>
|
||||
</x-alert>
|
||||
Reference in new issue
Block a user