fix(ui): refine service resources and settings section styling

This commit is contained in:
Andras Bacsai
2026-10-21 21:01:24 +02:00
parent 8255f85a50
commit 8d400e3d6b
5 changed files with 50 additions and 56 deletions
+9 -1
View File
@@ -2712,6 +2712,14 @@ input[type="search"]::-webkit-search-results-decoration {
padding: 0;
}
/* The well does not clip (floating panels must escape it), so a filled table
header row needs the well's inner top radius, or its corners poke out. */
.application-settings-section-body.is-flush > :first-child,
.application-settings-section-body.is-flush > :first-child > :first-child {
border-top-left-radius: calc(0.5rem - 1px);
border-top-right-radius: calc(0.5rem - 1px);
}
/* Empty states inside cards keep the same inset as other card content. */
.application-settings-section-body:has(> .empty-state:only-child),
.application-settings-section-body.is-flush:has(> .empty-state:only-child),
@@ -2847,6 +2855,7 @@ input[type="search"]::-webkit-search-results-decoration {
.dark .data-table-header {
background: rgba(255, 255, 255, 0.02);
color: var(--color-fg-faint);
}
.data-table > .env-table-item {
@@ -2868,7 +2877,6 @@ input[type="search"]::-webkit-search-results-decoration {
.data-table-row:hover {
background: rgba(0, 0, 0, 0.02);
color: var(--color-fg-faint);
}
.dark .data-table-row:hover {
+2 -2
View File
@@ -37,8 +37,8 @@
:class="{ 'z-[1000]': resourceActionsOpen }"
class="app-topbar hidden lg:flex fixed top-0 inset-x-0 z-50 h-12 items-center bg-white/95 dark:bg-panel/95 backdrop-blur">
{{-- Brand (width tracks sidebar) --}}
<div class="app-topbar-brand flex items-center gap-2 h-full shrink-0 border-r border-b border-black/[0.06] bg-neutral-50 dark:border-white/[0.04] dark:bg-app transition-[width] duration-200"
:class="collapsed ? 'w-16 justify-center px-0' : 'w-56 px-4'">
<div class="app-topbar-brand flex items-center gap-2 h-full shrink-0 border-r border-black/[0.06] bg-neutral-50 dark:border-white/[0.04] dark:bg-app transition-[width] duration-200"
:class="collapsed ? 'w-16 justify-center px-0 border-b' : 'w-56 px-4'">
<div class="flex items-baseline gap-1.5 min-w-0">
<a href="/" {{ wireNavigate() }} title="Coolify"
class="flex shrink-0 items-center hover:opacity-80 transition-opacity">
@@ -30,55 +30,49 @@
localStorage.setItem('service-compose-resources-view', mode);
}
}">
<div class="mb-3 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div>
<h2 class="text-base font-semibold text-black dark:text-fg">Compose resources</h2>
<p class="mt-1 text-sm text-neutral-500 dark:text-fg-dim">
Applications and databases defined in this service.
</p>
</div>
<div class="flex w-full items-center justify-between gap-2 sm:w-auto sm:justify-start">
<x-application.settings-section id="compose-resources-section" title="Compose resources"
description="Applications and databases defined in this service." flush>
<x-slot:actions>
<x-canvas-view-toggle />
<a class="button" target="_blank" href="{{ $service->documentation() }}">
Documentation
<x-reicon name="external-link" class="size-4" />
</a>
</x-slot:actions>
<div :class="viewMode === 'grid'
? 'grid grid-cols-1 gap-3 p-3 sm:grid-cols-2'
: 'overflow-x-auto rounded-lg'">
@if ($applications->isNotEmpty() || $databases->isNotEmpty())
<div x-cloak x-show="viewMode === 'table'"
class="grid min-w-[48rem] grid-cols-[minmax(14rem,1fr)_minmax(12rem,1fr)_12rem_5rem] gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<div>Resource</div>
<div>Image</div>
<div class="justify-self-start">Status</div>
<div></div>
</div>
@endif
@if ($applications->isEmpty() && $databases->isEmpty())
<div class="p-4 sm:col-span-2">
<x-empty title="No compose resources"
description="No applications or databases are defined in this Docker Compose file."
icon-name="grid" />
</div>
@endif
@foreach ($applications as $application)
<livewire:project.service.resource-card :service="$service" :resource="$application"
:parameters="$parameters"
wire:key="service-application-card-{{ $application->id }}" />
@endforeach
@foreach ($databases as $database)
<livewire:project.service.resource-card :service="$service" :resource="$database"
:parameters="$parameters"
wire:key="service-database-card-{{ $database->id }}" />
@endforeach
</div>
</div>
<div :class="viewMode === 'grid'
? 'grid grid-cols-1 gap-3 sm:grid-cols-2'
: 'overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]'">
@if ($applications->isNotEmpty() || $databases->isNotEmpty())
<div x-cloak x-show="viewMode === 'table'"
class="grid min-w-[48rem] grid-cols-[minmax(14rem,1fr)_minmax(12rem,1fr)_12rem_5rem] gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<div>Resource</div>
<div>Image</div>
<div class="justify-self-start">Status</div>
<div></div>
</div>
@endif
@if ($applications->isEmpty() && $databases->isEmpty())
<div
class="application-settings-section overflow-hidden sm:col-span-2">
<x-empty title="No compose resources"
description="No applications or databases are defined in this Docker Compose file."
icon-name="grid" />
</div>
@endif
@foreach ($applications as $application)
<livewire:project.service.resource-card :service="$service" :resource="$application"
:parameters="$parameters"
wire:key="service-application-card-{{ $application->id }}" />
@endforeach
@foreach ($databases as $database)
<livewire:project.service.resource-card :service="$service" :resource="$database"
:parameters="$parameters"
wire:key="service-database-card-{{ $database->id }}" />
@endforeach
</div>
</x-application.settings-section>
</div>
@elseif ($currentRoute === 'project.service.analytics')
<livewire:project.service.analytics :service="$service"
@@ -11,15 +11,7 @@
<div class="application-settings-form flex w-full flex-col gap-6">
@if ($server->isFunctional())
<div class="flex flex-wrap items-start justify-between gap-3 px-1">
<div>
<h2 class="text-sm! font-medium text-neutral-950 dark:text-fg">
Dynamic configurations
</h2>
<p class="mt-1 text-xs text-neutral-500 dark:text-fg-dim">
Manage additional proxy routes, middleware, and services loaded at runtime.
</p>
</div>
<div class="flex flex-wrap items-center justify-end gap-3 px-1">
<div class="flex items-center gap-2">
<x-forms.button wire:click="loadDynamicConfigurations">
<x-reicon name="refresh" class="size-3.5" />
@@ -258,7 +258,7 @@ it('keeps domain settings out of the overview and supports editing and removal',
->screenshot(filename: 'service-domain-removal-confirmation')
->click('button:has([x-text="step2ButtonText"]):visible')
->assertDontSee('https://long-public-domain-for-the-service.example.com')
->assertSee('1 domain across 1 service')
->assertSee('https://second.example.com')
->click('[aria-label="Settings for https://second.example.com"]')
->assertSee('www redirect')
->assertValue('#editingDomainParts-host', 'second.example.com')