Files
coolify/resources/views/components/shared-variables/editor.blade.php
Andras Bacsai 0a35909ddf feat(ui): standardize paginated tables and responsive dropdowns
Add reusable pagination and page-size controls, improve mobile dropdown positioning, and migrate paginated views to consistent table components.
2026-08-16 00:58:23 +02:00

135 lines
7.1 KiB
PHP

@props([
'resource',
'variables',
'type',
'title',
'view',
'variablesLabel',
])
@php
$alphabeticalPositions = $variables->sortBy('key')->values()->pluck('id')->flip();
$sharedVariableRows = $variables
->map(fn($variable) => [
'key' => mb_strtolower($variable->key),
'comment' => mb_strtolower($variable->comment ?? ''),
'scope' => mb_strtolower(str($type)->headline()),
])
->values();
@endphp
<x-shared-variables.layout>
<div class="application-settings-form w-full" x-data="{
sharedSearch: '',
sharedSort: 'alphabetical',
sortOpen: false,
rows: @js($sharedVariableRows),
get filteredCount() {
const query = this.sharedSearch.trim().toLowerCase();
if (!query) return this.rows.length;
return this.rows.filter(row => [row.key, row.comment, row.scope].some(value => value.includes(query))).length;
}
}">
<x-application.settings-section :title="$title" flush>
<x-slot:actions>
<x-forms.button type="button" wire:click="switch" class="whitespace-nowrap">
<x-reicon :name="$view === 'normal' ? 'browser-code' : 'unordered-list'" class="size-3.5" />
<span class="max-sm:hidden">{{ $view === 'normal' ? 'Developer view' : 'Normal view' }}</span>
<span class="sm:hidden">{{ $view === 'normal' ? 'Developer' : 'Normal' }}</span>
</x-forms.button>
</x-slot:actions>
@if ($view === 'normal')
<div
class="flex flex-col gap-3 border-b border-neutral-200 p-3 sm:flex-row sm:items-center sm:justify-between dark:border-white/[0.08]">
<div class="relative w-full sm:max-w-sm">
<x-reicon name="search"
class="pointer-events-none absolute top-1/2 left-2.5 z-10 size-3.5 -translate-y-1/2 text-neutral-400 dark:text-fg-faint" />
<input x-model.debounce.150ms="sharedSearch" type="search" placeholder="Search variables"
class="h-8! w-full rounded-lg! border-neutral-200! bg-white! py-0! pr-8! pl-8! text-[12px]! shadow-none! placeholder:text-neutral-400 focus:border-accent! focus:ring-0! dark:border-white/[0.08]! dark:bg-white/[0.035]! dark:text-fg! dark:placeholder:text-fg-faint">
<button x-cloak x-show="sharedSearch" @click="sharedSearch = ''" type="button"
class="absolute top-1/2 right-2 flex size-5 -translate-y-1/2 items-center justify-center rounded text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.07] dark:hover:text-fg"
aria-label="Clear search">
<x-reicon name="x" class="size-3" />
</button>
</div>
<div class="flex items-center gap-2">
<x-table.dropdown panel-class="w-48!">
<x-slot:trigger><button type="button" class="button" aria-haspopup="listbox" :aria-expanded="open">
<x-reicon name="sort-direction" class="size-3.5" />
Sort
</button></x-slot:trigger>
<button type="button" class="listbox-option"
@click="sharedSort = 'alphabetical'; close()">
<span>Alphabetical</span>
<svg x-show="sharedSort === 'alphabetical'" class="size-3.5 shrink-0" viewBox="0 0 24 24"
fill="none">
<path d="M5 12l5 5 9-11" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</button>
<button type="button" class="listbox-option"
@click="sharedSort = 'creation'; close()">
<span>Creation order</span>
<svg x-show="sharedSort === 'creation'" class="size-3.5 shrink-0" viewBox="0 0 24 24"
fill="none">
<path d="M5 12l5 5 9-11" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</button>
</x-table.dropdown>
@can('update', $resource)
<x-modal-input title="New Shared Variable">
<x-slot:content>
<button type="button"
class="button button-highlighted">
<x-reicon name="plus" class="size-3.5" />
Add variable
</button>
</x-slot:content>
<livewire:project.shared.environment-variable.add :shared="true" />
</x-modal-input>
@endcan
</div>
</div>
@if ($variables->isEmpty())
<div class="p-3">
<x-empty title="No shared variables"
description="Add a variable to make it available to resources in this scope."
icon-name="variables" size="sm" />
</div>
@else
<div class="data-table flex w-full flex-col">
<div class="data-table-header env-table-grid-shared order-[-1]">
<span>Name</span>
<span>Scope</span>
<span>Comment</span>
<span class="text-center">Multiline</span>
<span></span>
</div>
@foreach ($variables as $env)
<livewire:project.shared.environment-variable.show
wire:key="shared-variable-{{ $type }}-{{ $env->id }}" :env="$env"
:type="$type" :tableAlphabeticalOrder="$alphabeticalPositions[$env->id]"
:tableCreationOrder="$loop->index" />
@endforeach
<div
class="order-[9999] flex min-h-11 items-center border-t border-neutral-200 px-4 text-[11px] text-neutral-500 dark:border-white/[0.08] dark:text-fg-faint">
<span x-text="`${filteredCount} ${filteredCount === 1 ? 'variable' : 'variables'}`"></span>
</div>
</div>
@endif
@else
<form wire:submit="submit" class="p-4">
<x-unsaved-bar action="submit" />
<x-forms.textarea canGate="update" :canResource="$resource" rows="20"
class="whitespace-pre-wrap" id="variables" wire:model="variables" monospace
:label="$variablesLabel" />
</form>
@endif
</x-application.settings-section>
</div>
</x-shared-variables.layout>