Phase 1 UI system

This commit is contained in:
Codex
2026-07-10 12:56:04 -05:00
parent 2ee16a6469
commit b45a9eccd6
30 changed files with 324 additions and 292 deletions
@@ -0,0 +1,12 @@
@props(['title', 'description', 'href' => null, 'label' => 'Open'])
<div class="tse-panel flex h-full flex-col p-5">
<h3 class="text-base font-semibold text-slate-950 dark:text-white">{{ $title }}</h3>
<p class="mt-2 flex-1 text-sm leading-6 text-slate-600 dark:text-slate-400">{{ $description }}</p>
@if ($href)
<a href="{{ $href }}" class="mt-4 inline-flex items-center text-sm font-semibold text-sky-700 hover:text-sky-900 dark:text-sky-300 dark:hover:text-sky-200">
{{ $label }}
<span aria-hidden="true" class="ms-1">-&gt;</span>
</a>
@endif
</div>
@@ -0,0 +1,15 @@
@props(['tone' => 'slate'])
@php
$tones = [
'sky' => 'bg-sky-100 text-sky-800 dark:bg-sky-950 dark:text-sky-200',
'emerald' => 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-200',
'amber' => 'bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-200',
'rose' => 'bg-rose-100 text-rose-800 dark:bg-rose-950 dark:text-rose-200',
'slate' => 'bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-200',
];
@endphp
<span {{ $attributes->merge(['class' => 'inline-flex items-center rounded-full px-2.5 py-1 text-xs font-semibold '.$tones[$tone]]) }}>
{{ $slot }}
</span>
@@ -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 transition ease-in-out duration-150']) }}>
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-xs font-semibold uppercase tracking-widest text-white transition duration-150 ease-in-out hover:bg-red-500 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 active:bg-red-700 dark:focus:ring-offset-slate-900']) }}>
{{ $slot }}
</button>
@@ -1 +1 @@
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-slate-700 transition duration-150 ease-in-out hover:bg-slate-100 focus:bg-slate-100 focus:outline-none dark:text-slate-200 dark:hover:bg-slate-800 dark:focus:bg-slate-800']) }}>{{ $slot }}</a>
@@ -1,4 +1,4 @@
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white'])
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-slate-900'])
@php
$alignmentClasses = match ($align) {
@@ -28,7 +28,7 @@ $width = match ($width) {
class="absolute z-50 mt-2 {{ $width }} rounded-md shadow-lg {{ $alignmentClasses }}"
style="display: none;"
@click="open = false">
<div class="rounded-md ring-1 ring-black ring-opacity-5 {{ $contentClasses }}">
<div class="rounded-md ring-1 ring-black ring-opacity-5 dark:ring-white/10 {{ $contentClasses }}">
{{ $content }}
</div>
</div>
+7 -4
View File
@@ -1,11 +1,14 @@
@props(['name', 'label', 'value' => '', 'textarea' => false, 'type' => 'text'])
@props(['name', 'label', 'value' => '', 'textarea' => false, 'type' => 'text', 'help' => null])
<div>
<label for="{{ $name }}" class="block text-sm font-medium text-gray-700">{{ $label }}</label>
<label for="{{ $name }}" class="block text-sm font-medium text-slate-800 dark:text-slate-200">{{ $label }}</label>
@if ($textarea)
<textarea id="{{ $name }}" name="{{ $name }}" rows="4" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">{{ old($name, $value) }}</textarea>
<textarea id="{{ $name }}" name="{{ $name }}" rows="4" class="mt-1 block w-full rounded-md border-slate-300 bg-white text-slate-950 shadow-sm focus:border-sky-500 focus:ring-sky-500 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-100">{{ old($name, $value) }}</textarea>
@else
<input id="{{ $name }}" type="{{ $type }}" name="{{ $name }}" value="{{ old($name, $value) }}" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<input id="{{ $name }}" type="{{ $type }}" name="{{ $name }}" value="{{ old($name, $value) }}" class="mt-1 block w-full rounded-md border-slate-300 bg-white text-slate-950 shadow-sm focus:border-sky-500 focus:ring-sky-500 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-100">
@endif
@if ($help)
<p class="mt-1 text-sm text-slate-500 dark:text-slate-400">{{ $help }}</p>
@endif
@error($name)
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@@ -1,7 +1,7 @@
@props(['messages'])
@if ($messages)
<ul {{ $attributes->merge(['class' => 'text-sm text-red-600 space-y-1']) }}>
<ul {{ $attributes->merge(['class' => 'space-y-1 text-sm text-red-600 dark:text-red-400']) }}>
@foreach ((array) $messages as $message)
<li>{{ $message }}</li>
@endforeach
@@ -1,5 +1,5 @@
@props(['value'])
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700']) }}>
<label {{ $attributes->merge(['class' => 'block text-sm font-medium text-slate-800 dark:text-slate-200']) }}>
{{ $value ?? $slot }}
</label>
@@ -2,8 +2,8 @@
@php
$classes = ($active ?? false)
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-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 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out';
? 'inline-flex items-center px-1 pt-1 border-b-2 border-sky-500 text-sm font-medium leading-5 text-slate-950 focus:outline-none focus:border-sky-700 transition duration-150 ease-in-out dark:text-white'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-slate-500 hover:text-slate-800 hover:border-slate-300 focus:outline-none focus:text-slate-800 focus:border-slate-300 transition duration-150 ease-in-out dark:text-slate-400 dark:hover:text-slate-100 dark:hover:border-slate-600 dark:focus:text-slate-100 dark:focus:border-slate-600';
@endphp
<a {{ $attributes->merge(['class' => $classes]) }}>
@@ -0,0 +1,19 @@
@props(['eyebrow' => null, 'title', 'description' => null])
<div class="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
<div>
@if ($eyebrow)
<p class="text-sm font-semibold uppercase tracking-wide text-sky-700 dark:text-sky-300">{{ $eyebrow }}</p>
@endif
<h1 class="text-2xl font-semibold tracking-tight text-slate-950 dark:text-white">{{ $title }}</h1>
@if ($description)
<p class="mt-2 max-w-3xl text-sm leading-6 text-slate-600 dark:text-slate-400">{{ $description }}</p>
@endif
</div>
@if (trim($slot) !== '')
<div class="flex flex-wrap items-center gap-2">
{{ $slot }}
</div>
@endif
</div>
@@ -1,3 +1,3 @@
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150']) }}>
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center rounded-md border border-transparent bg-sky-600 px-4 py-2 text-xs font-semibold uppercase tracking-widest text-white transition duration-150 ease-in-out hover:bg-sky-700 focus:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 active:bg-sky-800 dark:focus:ring-offset-slate-900']) }}>
{{ $slot }}
</button>
@@ -2,8 +2,8 @@
@php
$classes = ($active ?? false)
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-sky-500 text-start text-base font-medium text-sky-800 bg-sky-50 focus:outline-none focus:text-sky-900 focus:bg-sky-100 focus:border-sky-700 transition duration-150 ease-in-out dark:bg-sky-950/40 dark:text-sky-200'
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-slate-600 hover:text-slate-900 hover:bg-slate-50 hover:border-slate-300 focus:outline-none focus:text-slate-900 focus:bg-slate-50 focus:border-slate-300 transition duration-150 ease-in-out dark:text-slate-300 dark:hover:text-white dark:hover:bg-slate-800 dark:hover:border-slate-600 dark:focus:text-white dark:focus:bg-slate-800 dark:focus:border-slate-600';
@endphp
<a {{ $attributes->merge(['class' => $classes]) }}>
@@ -1,3 +1,3 @@
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150']) }}>
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center rounded-md border border-slate-300 bg-white px-4 py-2 text-xs font-semibold uppercase tracking-widest text-slate-700 shadow-sm transition duration-150 ease-in-out hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 disabled:opacity-25 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800 dark:focus:ring-offset-slate-900']) }}>
{{ $slot }}
</button>
@@ -0,0 +1,9 @@
@props(['label', 'value', 'description' => null])
<div class="tse-panel p-5">
<p class="text-sm font-medium text-slate-500 dark:text-slate-400">{{ $label }}</p>
<p class="mt-2 text-3xl font-semibold tracking-tight text-slate-950 dark:text-white">{{ $value }}</p>
@if ($description)
<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">{{ $description }}</p>
@endif
</div>
@@ -1,3 +1,3 @@
@props(['disabled' => false])
<input @disabled($disabled) {{ $attributes->merge(['class' => 'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm']) }}>
<input @disabled($disabled) {{ $attributes->merge(['class' => 'rounded-md border-slate-300 bg-white text-slate-950 shadow-sm focus:border-sky-500 focus:ring-sky-500 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-100']) }}>
@@ -0,0 +1,21 @@
<button
type="button"
x-data="{
dark: document.documentElement.classList.contains('dark'),
toggle() {
this.dark = ! this.dark;
document.documentElement.classList.toggle('dark', this.dark);
localStorage.setItem('tse-theme', this.dark ? 'dark' : 'light');
}
}"
x-on:click="toggle()"
class="inline-flex h-9 w-9 items-center justify-center rounded-md border border-slate-200 bg-white text-slate-600 shadow-sm transition hover:border-slate-300 hover:text-slate-950 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300 dark:hover:border-slate-600 dark:hover:text-white dark:focus:ring-offset-slate-900"
aria-label="Toggle color theme"
>
<svg x-show="!dark" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M10 2a1 1 0 0 1 1 1v1a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1Zm0 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm7-5a1 1 0 1 1 0 2h-1a1 1 0 1 1 0-2h1ZM5 10a1 1 0 0 1-1 1H3a1 1 0 1 1 0-2h1a1 1 0 0 1 1 1Zm10.657-5.657a1 1 0 0 1 0 1.414l-.707.707a1 1 0 1 1-1.414-1.414l.707-.707a1 1 0 0 1 1.414 0ZM6.464 13.536a1 1 0 0 1 0 1.414l-.707.707a1 1 0 0 1-1.414-1.414l.707-.707a1 1 0 0 1 1.414 0Zm9.193 2.121a1 1 0 0 1-1.414 0l-.707-.707a1 1 0 0 1 1.414-1.414l.707.707a1 1 0 0 1 0 1.414ZM6.464 6.464A1 1 0 0 1 5.05 6.464l-.707-.707a1 1 0 0 1 1.414-1.414l.707.707a1 1 0 0 1 0 1.414ZM10 15a1 1 0 0 1 1 1v1a1 1 0 1 1-2 0v-1a1 1 0 0 1 1-1Z"/>
</svg>
<svg x-show="dark" x-cloak class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M7.455 2.004a.75.75 0 0 1 .79.927 7.5 7.5 0 0 0 8.824 8.824.75.75 0 0 1 .927.79A8.5 8.5 0 1 1 7.455 2.004Z" clip-rule="evenodd"/>
</svg>
</button>