feat(ui): add configurable page widths and searchable controls
Add full-width and centered layout preferences across the app shell and workspaces. Replace page-size selects with dropdowns and add searchable breadcrumb switching.
This commit is contained in:
parent
b3b4d8a5f1
commit
5b517f21be
75 changed files with 263 additions and 148 deletions
|
|
@ -1,9 +1,12 @@
|
|||
@props(['label', 'items', 'title'])
|
||||
|
||||
<span class="shrink-0 px-0.5 text-neutral-300 dark:text-fg-faint">/</span>
|
||||
<div class="relative min-w-0 shrink" x-data="{ open: false }" @keydown.escape.window="open = false">
|
||||
<div class="relative min-w-0 shrink" x-data="{ open: false, search: '' }" @keydown.escape.window="open = false"
|
||||
@click.outside="open = false">
|
||||
<div class="flex h-8 min-w-0 items-center gap-1">
|
||||
<button type="button" @click="open = !open" @click.outside="open = false" title="Switch resource"
|
||||
<button type="button"
|
||||
@click="open = !open; if (open) { search = ''; $nextTick(() => $refs.search.focus()) }"
|
||||
title="Switch resource"
|
||||
class="flex h-8 min-w-0 items-center gap-1.5 rounded-md px-2 opacity-70 transition-[background-color,opacity] hover:bg-neutral-100 hover:opacity-100 dark:hover:bg-white/[0.05]">
|
||||
<span class="min-w-0 truncate font-semibold text-black dark:text-fg">{{ $label }}</span>
|
||||
<svg class="size-4 shrink-0 text-neutral-400 dark:text-fg-faint" viewBox="0 0 24 24" fill="none">
|
||||
|
|
@ -18,11 +21,19 @@ class="flex h-8 min-w-0 items-center gap-1.5 rounded-md px-2 opacity-70 transiti
|
|||
|
||||
<div x-show="open" x-cloak x-transition.opacity.duration.120ms
|
||||
class="listbox-panel scrollbar left-0! z-[90]! max-h-80! min-w-56 max-w-72">
|
||||
<div class="searchable-listbox-search">
|
||||
<x-reicon name="search"
|
||||
class="pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-neutral-400 dark:text-fg-faint" />
|
||||
<input x-ref="search" x-model.debounce.150ms="search" type="search"
|
||||
autocomplete="off" placeholder="Search {{ strtolower($title) }}"
|
||||
class="searchable-listbox-search-input" @keydown.escape.stop="open = false">
|
||||
</div>
|
||||
<div class="px-2 py-1 text-[10px] font-semibold uppercase tracking-wide text-neutral-400 dark:text-fg-faint">
|
||||
{{ $title }}
|
||||
</div>
|
||||
@foreach ($items as $item)
|
||||
<a href="{{ $item['href'] }}" {{ wireNavigate() }} @click="open = false"
|
||||
x-show="@js(strtolower($item['label'])).includes(search.toLowerCase())"
|
||||
class="listbox-option {{ $item['active'] ? 'bg-neutral-100 font-medium text-black dark:bg-white/[0.07] dark:text-fg' : '' }}">
|
||||
<span class="min-w-0 flex-1 truncate">{{ $item['label'] }}</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@
|
|||
];
|
||||
@endphp
|
||||
|
||||
<section class="application-settings-workspace w-full max-w-[1180px]">
|
||||
<section class="application-settings-workspace w-full max-w-none">
|
||||
<header class="settings-mobile-header xl:hidden">
|
||||
<h1 class="settings-mobile-title">Notifications</h1>
|
||||
<p class="settings-mobile-description">Configure how your team receives deployment and system alerts.</p>
|
||||
</header>
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="Notification settings"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -5,35 +5,16 @@
|
|||
'storageKey' => null,
|
||||
])
|
||||
|
||||
<label class="mb-0! flex h-7 items-center gap-1.5 text-[11px] text-neutral-500 dark:text-fg-dim"
|
||||
<div class="mb-0! flex h-7 items-center gap-1.5 text-[11px] text-neutral-500 dark:text-fg-dim"
|
||||
x-data="{
|
||||
selectedPageSize: @js((int) $options[0]),
|
||||
customPageSize: @js((int) $options[0]),
|
||||
customizingPageSize: false,
|
||||
syncCustomOption(value) {
|
||||
const select = this.$refs.pageSizePreset;
|
||||
let customOption = select?.querySelector('[data-custom-page-size]');
|
||||
if (@js(array_map('intval', $options)).includes(Number(value))) {
|
||||
customOption?.remove();
|
||||
} else if (select) {
|
||||
if (!customOption) {
|
||||
customOption = document.createElement('option');
|
||||
customOption.dataset.customPageSize = '';
|
||||
select.insertBefore(customOption, select.lastElementChild);
|
||||
}
|
||||
customOption.value = String(value);
|
||||
customOption.textContent = String(value);
|
||||
}
|
||||
if (select) select.value = String(value);
|
||||
},
|
||||
applyPageSize(value) {
|
||||
const pageSizeValue = Math.min(100, Math.max(1, Number(value) || 1));
|
||||
this.selectedPageSize = pageSizeValue;
|
||||
this.customPageSize = pageSizeValue;
|
||||
this.customizingPageSize = false;
|
||||
this.$nextTick(() => {
|
||||
this.syncCustomOption(pageSizeValue);
|
||||
});
|
||||
@if ($livewire)
|
||||
$wire.set(@js($model), pageSizeValue);
|
||||
@else
|
||||
|
|
@ -51,25 +32,32 @@
|
|||
if (savedPageSize >= 1 && savedPageSize <= 100) applyPageSize(savedPageSize);
|
||||
@endif
|
||||
">
|
||||
<span class="hidden sm:inline">Rows</span>
|
||||
<span x-show="!customizingPageSize" class="relative inline-flex h-7 w-12 items-center">
|
||||
<select x-ref="pageSizePreset" aria-label="Items per page"
|
||||
x-on:change="$el.value === 'custom' ? (customizingPageSize = true, $nextTick(() => $refs.customPageSize.focus())) : applyPageSize($el.value)"
|
||||
class="peer absolute inset-0 z-10 h-7! w-12! cursor-pointer opacity-0">
|
||||
<x-table.dropdown panel-class="min-w-24!">
|
||||
<x-slot:trigger>
|
||||
<button type="button" aria-label="Items per page" aria-haspopup="listbox" :aria-expanded="open"
|
||||
class="inline-flex h-7! w-12! items-center justify-between border-0 px-1 text-[11px]! leading-none! tabular-nums text-neutral-500 transition-colors hover:text-black dark:text-fg-dim dark:hover:text-fg">
|
||||
<span x-text="selectedPageSize"></span>
|
||||
<x-reicon name="chevron-down" class="size-3 text-neutral-400 dark:text-fg-faint" />
|
||||
</button>
|
||||
</x-slot:trigger>
|
||||
@foreach ($options as $option)
|
||||
<option value="{{ $option }}">{{ $option }}</option>
|
||||
<button type="button" class="listbox-option" role="option"
|
||||
:aria-selected="selectedPageSize === {{ (int) $option }}"
|
||||
x-on:click="applyPageSize({{ (int) $option }})">
|
||||
<span>{{ $option }}</span>
|
||||
<x-reicon x-show="selectedPageSize === {{ (int) $option }}" name="check" class="size-3.5" />
|
||||
</button>
|
||||
@endforeach
|
||||
<option value="custom">Custom…</option>
|
||||
</select>
|
||||
<span
|
||||
class="pointer-events-none inline-flex h-7 w-12 items-center justify-between border-0 px-1 text-[11px]! leading-none! tabular-nums text-neutral-500 transition-colors peer-hover:text-black dark:text-fg-dim dark:peer-hover:text-fg">
|
||||
<span x-text="selectedPageSize"></span>
|
||||
<x-reicon name="chevron-down" class="size-3 text-neutral-400 dark:text-fg-faint" />
|
||||
</span>
|
||||
<button type="button" class="listbox-option" role="option"
|
||||
x-on:click="customizingPageSize = true; $nextTick(() => $refs.customPageSize.focus())">
|
||||
Custom…
|
||||
</button>
|
||||
</x-table.dropdown>
|
||||
</span>
|
||||
<input x-cloak x-show="customizingPageSize" x-ref="customPageSize" x-model.number="customPageSize"
|
||||
x-on:keydown.enter.prevent="applyPageSize(customPageSize)" x-on:keydown.escape.prevent="customizingPageSize = false"
|
||||
x-on:blur="if (customizingPageSize) applyPageSize(customPageSize)" type="number" min="1" max="100" inputmode="numeric"
|
||||
aria-label="Custom items per page"
|
||||
class="mb-0! h-7! w-14! rounded-md! border-neutral-200! bg-transparent! px-1.5! py-0! text-[11px]! tabular-nums shadow-none! focus:border-neutral-300! focus:ring-0! dark:border-white/[0.08]! dark:text-fg-dim!" />
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@
|
|||
])->filter();
|
||||
@endphp
|
||||
|
||||
<section class="application-settings-workspace w-full max-w-[1180px]">
|
||||
<section class="application-settings-workspace w-full max-w-none">
|
||||
<header class="settings-mobile-header xl:hidden">
|
||||
<h1 class="settings-mobile-title">Keys & Tokens</h1>
|
||||
<p class="settings-mobile-description">Manage SSH keys, cloud credentials, and API access tokens.</p>
|
||||
</header>
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="Keys and tokens"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@
|
|||
];
|
||||
@endphp
|
||||
|
||||
<section class="application-settings-workspace w-full max-w-[1180px]">
|
||||
<section class="application-settings-workspace w-full max-w-none">
|
||||
<header class="settings-mobile-header xl:hidden">
|
||||
<h1 class="settings-mobile-title">Instance Settings</h1>
|
||||
<p class="settings-mobile-description">Configure global settings for this Coolify instance.</p>
|
||||
</header>
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="Instance settings"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
])
|
||||
|
||||
{{-- Same 1180px shell as the workspace. Title hidden only at xl+ (full desktop). --}}
|
||||
<div class="mx-auto w-full max-w-[1180px]">
|
||||
<div class="mx-auto w-full max-w-none">
|
||||
<x-dashboard.navbar section="settings" :title="$title" :subtitle="$subtitle" :titleOnDesktop="false">
|
||||
@isset($titleActions)
|
||||
<x-slot:titleActions>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
];
|
||||
@endphp
|
||||
|
||||
<section class="w-full max-w-[1180px]">
|
||||
<section class="w-full max-w-none">
|
||||
<header class="mb-6 xl:hidden">
|
||||
<h1 class="text-[24px]! leading-7! font-semibold! tracking-tight!">Shared variables</h1>
|
||||
<p class="mt-1 text-[13px] text-neutral-500 dark:text-fg-dim">Reusable environment variables across resources</p>
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@
|
|||
])->filter();
|
||||
@endphp
|
||||
|
||||
<section class="application-settings-workspace w-full max-w-[1180px]">
|
||||
<section class="application-settings-workspace w-full max-w-none">
|
||||
<header class="settings-mobile-header xl:hidden">
|
||||
<h1 class="settings-mobile-title">Team</h1>
|
||||
<p class="settings-mobile-description">Manage your team, members, and access settings.</p>
|
||||
</header>
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="Team settings"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
open: false,
|
||||
appearanceOpen: false,
|
||||
theme: localStorage.getItem('theme') === 'purple' ? 'custom' : (localStorage.getItem('theme') || 'dark'),
|
||||
pageWidth: localStorage.getItem('pageWidth') || 'full',
|
||||
themeColor: localStorage.getItem('themeColor') || '#6b16ed',
|
||||
themeColorFrame: null,
|
||||
avatarUrl: @js($user?->avatar_path ? route('profile.avatar', ['v' => $user->updated_at->timestamp]) : null),
|
||||
|
|
@ -32,6 +33,11 @@
|
|||
document.documentElement.style.setProperty('--theme-accent-foreground', window.themeAccentForeground(this.themeColor));
|
||||
document.querySelector('meta[name=theme-color]')?.setAttribute('content', isDark ? '#101010' : '#ffffff');
|
||||
},
|
||||
setWidth(width) {
|
||||
this.pageWidth = width;
|
||||
localStorage.setItem('pageWidth', width);
|
||||
window.dispatchEvent(new CustomEvent('page-width-changed', { detail: width }));
|
||||
},
|
||||
previewThemeColor(color) {
|
||||
this.themeColor = color;
|
||||
|
||||
|
|
@ -150,6 +156,25 @@ class="size-3.5 text-coollabs dark:text-warning" viewBox="0 0 12 12" fill="none"
|
|||
</button>
|
||||
@endif
|
||||
@endforeach
|
||||
<div class="my-1 h-px bg-neutral-200 dark:bg-white/[0.07]"></div>
|
||||
<div class="px-2 pt-1 pb-0.5 text-[10px] font-medium tracking-wide text-neutral-400 uppercase dark:text-fg-faint">
|
||||
Page width
|
||||
</div>
|
||||
@foreach ([
|
||||
['value' => 'full', 'label' => 'Full width'],
|
||||
['value' => 'centered', 'label' => 'Centered'],
|
||||
] as $option)
|
||||
<button type="button" @click="setWidth('{{ $option['value'] }}')"
|
||||
class="flex h-8 w-full items-center justify-between rounded-md px-2 text-left text-xs text-neutral-600 transition-colors hover:bg-neutral-200 hover:text-neutral-950 dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg">
|
||||
<span>{{ $option['label'] }}</span>
|
||||
<svg x-show="pageWidth === '{{ $option['value'] }}'"
|
||||
class="size-3.5 text-coollabs dark:text-warning" viewBox="0 0 12 12" fill="none"
|
||||
aria-hidden="true">
|
||||
<path d="m2.5 6.25 2.1 2.1 4.9-5" stroke="currentColor" stroke-width="1.4"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="my-1 h-px bg-neutral-200 dark:bg-white/[0.07]"></div>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<div x-data="{
|
||||
open: false,
|
||||
collapsed: localStorage.getItem('sidebarCollapsed') === 'true',
|
||||
pageWidth: localStorage.getItem('pageWidth') || 'full',
|
||||
sidebarReady: false,
|
||||
init() {
|
||||
this.$nextTick(() => {
|
||||
|
|
@ -22,7 +23,8 @@
|
|||
this.collapsed = !this.collapsed;
|
||||
localStorage.setItem('sidebarCollapsed', this.collapsed);
|
||||
}
|
||||
}" @open-global-search.window="open = false" x-cloak class="dark:text-inherit text-black">
|
||||
}" @open-global-search.window="open = false" @page-width-changed.window="pageWidth = $event.detail" x-cloak
|
||||
class="dark:text-inherit text-black">
|
||||
<livewire:deployments-indicator />
|
||||
|
||||
{{-- ============ DESKTOP TOP BAR ============ --}}
|
||||
|
|
@ -128,7 +130,7 @@ class="hidden shrink-0 items-center"></div>
|
|||
<main
|
||||
class="min-h-screen bg-white dark:bg-panel px-5 py-6 sm:px-8 lg:px-10 lg:pt-[calc(3rem+1.75rem)] lg:pb-10"
|
||||
:class="[collapsed ? 'lg:ml-16' : 'lg:ml-56', sidebarReady ? 'transition-[margin] duration-200' : '']">
|
||||
<div class="mx-auto w-full max-w-[1400px]">
|
||||
<div class="w-full" :class="pageWidth === 'centered' ? 'mx-auto max-w-[1400px]' : 'max-w-none'">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div>
|
||||
<x-slot:title>Admin | Coolify</x-slot>
|
||||
<div class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
<div class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
<section class="grid gap-3 sm:grid-cols-3">
|
||||
<div class="rounded-[10px] border border-neutral-200 bg-white p-4 dark:border-white/[0.07] dark:bg-surface">
|
||||
<div class="text-xs font-medium text-neutral-500 dark:text-fg-dim">Current user</div>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
:title="$destination->name" subtitle="Applications, databases, and services on this network"
|
||||
:mobileTitleOnly="true" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
@include('livewire.destination.sidebar', ['destination' => $destination])
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
<x-dashboard.navbar section="destination" :parameters="['destination_uuid' => $destination->uuid]"
|
||||
:title="$name" :subtitle="$destinationSubtitle" :mobileTitleOnly="true" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
@include('livewire.destination.sidebar', ['destination' => $destination])
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<div x-data="{
|
||||
theme: localStorage.getItem('theme') === 'purple' ? 'custom' : (localStorage.getItem('theme') || 'dark'),
|
||||
themeColor: localStorage.getItem('themeColor') || '#6b16ed',
|
||||
pageWidth: localStorage.getItem('pageWidth') || 'full',
|
||||
themeColorFrame: null,
|
||||
init() {
|
||||
localStorage.setItem('theme', this.theme);
|
||||
|
|
@ -13,6 +14,11 @@
|
|||
localStorage.setItem('theme', type);
|
||||
this.applyTheme();
|
||||
},
|
||||
setWidth(width) {
|
||||
this.pageWidth = width;
|
||||
localStorage.setItem('pageWidth', width);
|
||||
window.dispatchEvent(new CustomEvent('page-width-changed', { detail: width }));
|
||||
},
|
||||
previewThemeColor(color) {
|
||||
this.themeColor = color;
|
||||
|
||||
|
|
@ -46,7 +52,7 @@
|
|||
document.documentElement.style.setProperty('--theme-accent-foreground', window.themeAccentForeground(this.themeColor));
|
||||
document.querySelector('meta[name=theme-color]')?.setAttribute('content', isDark ? '#101010' : '#ffffff');
|
||||
},
|
||||
}" class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
}" class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
<div>
|
||||
|
|
@ -106,5 +112,45 @@ class="absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0" />
|
|||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
<div>
|
||||
<h2>Page width</h2>
|
||||
<p>Choose how content uses the available browser width.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="application-settings-section-body grid gap-3 sm:grid-cols-2">
|
||||
@foreach ([
|
||||
['value' => 'full', 'label' => 'Full width', 'description' => 'Use all available space for page content.'],
|
||||
['value' => 'centered', 'label' => 'Centered', 'description' => 'Keep content centered at a comfortable maximum width.'],
|
||||
] as $option)
|
||||
<button type="button" @click="setWidth('{{ $option['value'] }}')"
|
||||
class="group overflow-hidden rounded-[10px] border border-neutral-200 bg-white text-left transition-[border-color,box-shadow] hover:border-neutral-300 hover:shadow-sm dark:border-white/[0.07] dark:bg-white/[0.025] dark:hover:border-white/[0.12]"
|
||||
:class="pageWidth === '{{ $option['value'] }}'
|
||||
? 'ring-1 ring-coollabs/30 border-coollabs/40 dark:ring-warning/30 dark:border-warning/40'
|
||||
: ''">
|
||||
<div class="flex h-20 items-center border-b border-neutral-200 bg-neutral-50 px-4 dark:border-white/[0.07] dark:bg-black/15">
|
||||
<div class="flex h-11 w-full gap-1.5 rounded-md border border-neutral-300 bg-white p-1.5 dark:border-white/15 dark:bg-[#181818]">
|
||||
<div class="w-3 shrink-0 rounded-sm bg-neutral-200 dark:bg-white/10"></div>
|
||||
<div @class([
|
||||
'h-full rounded-sm bg-neutral-200 dark:bg-white/10',
|
||||
'w-full' => $option['value'] === 'full',
|
||||
'mx-auto w-2/3' => $option['value'] === 'centered',
|
||||
])></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-sm font-semibold text-black dark:text-fg">{{ $option['label'] }}</span>
|
||||
<x-reicon name="check-circle" class="size-4 text-coollabs dark:text-warning"
|
||||
x-show="pageWidth === '{{ $option['value'] }}'" x-cloak />
|
||||
</div>
|
||||
<p class="mt-1 text-xs leading-5 text-neutral-500 dark:text-fg-dim">{{ $option['description'] }}</p>
|
||||
</div>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
}"
|
||||
@close-email-change-modal.window="emailModalOpen = false">
|
||||
<x-slot:title>Profile | Coolify</x-slot>
|
||||
<div class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
<div class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
<section class="application-settings-section" x-data="{
|
||||
preview: null,
|
||||
processing: false,
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@
|
|||
<livewire:project.application.heading :application="$application"
|
||||
wire:key="application-heading-backup-index-{{ $application->id }}" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-application.configuration-sidebar :application="$application"
|
||||
current-route="project.application.backup.index" />
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
<livewire:project.application.heading :application="$application" wire:key="application-heading-backup-show" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-backup-sidebar context="application" :parameters="$parameters" :section="$section" />
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
<livewire:project.shared.configuration-checker :resource="$application" />
|
||||
<livewire:project.application.heading :application="$application" :wire:key="'application-heading-'.$currentRoute" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-application.configuration-sidebar :application="$application" :current-route="$currentRoute" />
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@
|
|||
|
||||
<section @class([
|
||||
'application-settings-workspace w-full',
|
||||
'mt-4 max-w-[1180px] lg:mt-0' => ! $embedded,
|
||||
'mt-4 max-w-none lg:mt-0' => ! $embedded,
|
||||
])>
|
||||
<div @class([
|
||||
'min-w-0',
|
||||
'grid gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10' => ! $embedded,
|
||||
'grid gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8' => ! $embedded,
|
||||
])>
|
||||
@unless ($embedded)
|
||||
<x-application.configuration-sidebar :application="$application"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
</x-slot>
|
||||
<livewire:project.shared.configuration-checker :resource="$application" />
|
||||
<livewire:project.application.heading :application="$application" wire:key="application-heading-deployment-show" />
|
||||
<section class="application-settings-workspace mt-4 flex min-h-0 w-full max-w-[1180px] flex-1 lg:mt-0">
|
||||
<div class="grid min-h-0 min-w-0 flex-1 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 flex min-h-0 w-full max-w-none flex-1 lg:mt-0">
|
||||
<div class="grid min-h-0 min-w-0 flex-1 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-application.configuration-sidebar :application="$application" :flush="true"
|
||||
current-route="project.application.deployment.show" />
|
||||
<div class="flex min-h-0 min-w-0 flex-col gap-4 xl:h-full xl:pt-px">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<nav wire:poll.10000ms="checkStatus" class="w-full max-w-[1180px] pb-4 md:pb-6 lg:pb-0">
|
||||
<nav wire:poll.10000ms="checkStatus" class="w-full max-w-none pb-4 md:pb-6 lg:pb-0">
|
||||
@php
|
||||
$routeIs = fn (string|array $routes): bool => \Illuminate\Support\Str::is($routes, $activeRouteName);
|
||||
// Settings covers all configuration sub-pages (General, Webhooks, Domains, …),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div>
|
||||
<x-slot:title>{{ data_get_str($project, 'name')->limit(10) }} > Clone | Coolify</x-slot>
|
||||
<div class="w-full max-w-[1180px]">
|
||||
<div class="w-full max-w-none">
|
||||
<header class="mb-5">
|
||||
<h1 class="truncate text-[24px]! leading-7! font-semibold! tracking-tight!">{{ $environment->name }}</h1>
|
||||
<p class="mt-1 text-[13px] text-neutral-500 dark:text-fg-dim">
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-backup-sidebar context="database" :parameters="$parameters" :section="$section" />
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<livewire:project.database.heading :database="$database" />
|
||||
|
||||
<div class="application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<div class="application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-database.configuration-sidebar :database="$database" current-route="project.database.backup.index" />
|
||||
<div class="application-settings-form flex min-w-0 flex-col gap-6">
|
||||
<x-application.settings-section title="Database backups"
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<livewire:project.database.heading :database="$database" />
|
||||
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-database.configuration-sidebar :database="$database" :current-route="$currentRoute" />
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<nav wire:poll.10000ms="checkStatus" class="w-full max-w-[1180px] pb-4 md:pb-6 lg:pb-0">
|
||||
<nav wire:poll.10000ms="checkStatus" class="w-full max-w-none pb-4 md:pb-6 lg:pb-0">
|
||||
@php
|
||||
$databasePageItems = [
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div>
|
||||
<x-slot:title>{{ data_get_str($project, 'name')->limit(10) }} > Edit | Coolify</x-slot>
|
||||
<div class="w-full max-w-[1180px]">
|
||||
<div class="w-full max-w-none">
|
||||
<header class="mb-5">
|
||||
<h1 class="truncate text-[24px]! leading-7! font-semibold! tracking-tight!">{{ $project->name }}</h1>
|
||||
<p class="mt-1 text-[13px] text-neutral-500 dark:text-fg-dim">Project settings</p>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div>
|
||||
<x-slot:title>{{ data_get_str($environment, 'name')->limit(10) }} > Edit | Coolify</x-slot>
|
||||
<div class="w-full max-w-[1180px]">
|
||||
<div class="w-full max-w-none">
|
||||
<header class="mb-5 flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div class="min-w-0">
|
||||
<h1 class="truncate text-[24px]! leading-7! font-semibold! tracking-tight!">{{ $environment->name }}</h1>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
<div class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
@if ($current_step === 'private_keys')
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
<div class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
@if ($github_apps->isEmpty())
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
<div class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
@if ($gitlab_apps->isEmpty())
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<div x-data x-init="$nextTick(() => { if ($refs.autofocusInput) $refs.autofocusInput.focus(); })"
|
||||
class="mt-8 flex w-full max-w-[1180px] flex-col gap-6 lg:mt-3">
|
||||
class="mt-8 flex w-full max-w-none flex-col gap-6 lg:mt-3">
|
||||
<form wire:submit="loadBranch">
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="mt-8 w-full max-w-[1180px] lg:mt-3">
|
||||
<div class="mt-8 w-full max-w-none lg:mt-3">
|
||||
<form wire:submit="submit">
|
||||
<section class="application-settings-section">
|
||||
<div class="application-settings-section-header">
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@
|
|||
]);
|
||||
@endphp
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="Service settings"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
<livewire:project.service.heading :service="$service" :parameters="$parameters" :query="$query" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
@if ($backup)
|
||||
<x-backup-sidebar context="service" :parameters="$backupParameters" :section="$section" />
|
||||
@else
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<nav wire:poll.10000ms="checkStatus" class="w-full max-w-[1180px] pb-4 md:pb-6 lg:pb-0">
|
||||
<nav wire:poll.10000ms="checkStatus" class="w-full max-w-none pb-4 md:pb-6 lg:pb-0">
|
||||
@php
|
||||
$servicePageItems = [
|
||||
[
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div>
|
||||
<livewire:project.service.heading :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
@if ($resourceType === 'database')
|
||||
<x-service-database.sidebar :parameters="$parameters" :serviceDatabase="$serviceDatabase" :isImportSupported="$isImportSupported" />
|
||||
@else
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@
|
|||
<livewire:project.service.heading :service="$service" :parameters="$parameters" :query="request()->query()"
|
||||
wire:key="service-heading-volume-backup-index" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-service.configuration-sidebar :service="$service"
|
||||
current-route="project.service.volume-backups.index" />
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<livewire:project.service.heading :service="$service" :parameters="$parameters" :query="request()->query()"
|
||||
wire:key="service-heading-volume-backup-show" />
|
||||
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-backup-sidebar context="service-volume" :parameters="$parameters" :section="$section" />
|
||||
|
||||
<div class="min-w-0">
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@
|
|||
@endphp
|
||||
|
||||
@if (in_array($type, ['application', 'database', 'service', 'server'], true))
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
@if ($type === 'server')
|
||||
<x-server.sidebar :server="$resource" activeMenu="terminal" />
|
||||
@elseif ($type === 'application')
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
@endif
|
||||
|
||||
@if ($consoleUnavailable)
|
||||
<section class="mt-8 w-full max-w-[1180px] xl:mt-0">
|
||||
<section class="mt-8 w-full max-w-none xl:mt-0">
|
||||
@if ($type === 'server')
|
||||
<x-empty size="lg" title="Terminal unavailable"
|
||||
description="This server is not functional or terminal access is disabled."
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
@endif
|
||||
</section>
|
||||
@else
|
||||
<section class="mt-8 mb-0! h-[calc(100dvh-8rem)] min-h-[32rem] w-full max-w-[1180px] xl:mt-0"
|
||||
<section class="mt-8 mb-0! h-[calc(100dvh-8rem)] min-h-[32rem] w-full max-w-none xl:mt-0"
|
||||
x-on:terminal-theme-selected="setTheme($event.detail.theme)"
|
||||
x-on:terminal-starting.window="syncTheme()"
|
||||
x-data="{
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@
|
|||
@endphp
|
||||
|
||||
@if (in_array($type, ['application', 'database', 'service'], true))
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
@if ($type === 'application')
|
||||
<x-application.configuration-sidebar :application="$resource" current-route="project.application.logs" />
|
||||
@elseif ($type === 'database')
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="advanced" />
|
||||
|
||||
<form wire:submit="submit" class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="ca-certificate" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="metrics" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="cloud-provider-token" />
|
||||
|
||||
<div class="application-settings-form w-full">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="cloudflare-tunnel" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="danger" />
|
||||
|
||||
<div class="application-settings-form w-full">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="destinations" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="docker-cleanup" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="log-drains" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<nav class="w-full max-w-[1180px] pb-3 lg:pb-0">
|
||||
<nav class="w-full max-w-none pb-3 lg:pb-0">
|
||||
<x-process-dialog @startproxy.window="processDialogOpen = true" closeWithX>
|
||||
<x-slot:title>Proxy Startup Logs</x-slot:title>
|
||||
<x-slot:content>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="private-key" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="proxy" activeSubMenu="dynamic-confs" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
<livewire:server.navbar :server="$server" />
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="proxy" activeSubMenu="logs" />
|
||||
<div class="application-settings-form w-full">
|
||||
<x-application.settings-section title="Proxy logs"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
<livewire:server.navbar :server="$server" />
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="proxy" activeSubMenu="configuration" />
|
||||
@if ($server->isFunctional())
|
||||
<div class="w-full">
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<div class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="resources" />
|
||||
<div class="application-settings-form min-w-0 w-full">
|
||||
<x-application.settings-section id="server-resources-section" title="Resources"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
</x-process-dialog>
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="security" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="security" />
|
||||
|
||||
<div class="application-settings-form w-full">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
<livewire:server.navbar :server="$server" />
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="sentinel" />
|
||||
<div class="application-settings-form w-full">
|
||||
<x-application.settings-section title="Sentinel logs"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
<livewire:server.navbar :server="$server" />
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="sentinel" />
|
||||
@if ($server->isFunctional())
|
||||
<div class="w-full">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="general" />
|
||||
<div class="w-full min-w-0">
|
||||
@if ($server->isLocalhost())
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="swarm" />
|
||||
|
||||
<div class="application-settings-form w-full">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<livewire:server.navbar :server="$server" />
|
||||
|
||||
<div
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-[1180px] min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
class="server-settings-workspace application-settings-workspace mt-4 grid w-full max-w-none min-w-0 gap-8 lg:mt-0 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<x-server.sidebar :server="$server" activeMenu="transfer" />
|
||||
|
||||
<div class="application-settings-form flex w-full flex-col gap-6">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
|
||||
<x-settings.layout>
|
||||
<div class="application-settings-form mx-auto flex w-full max-w-[1180px] min-w-0 flex-col gap-6">
|
||||
<div class="application-settings-form mx-auto flex w-full max-w-none min-w-0 flex-col gap-6">
|
||||
@if ($server->isFunctional())
|
||||
@if (isset($database) && isset($backup))
|
||||
<form wire:submit="submit">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
|
||||
<x-settings.layout>
|
||||
<div class="application-settings-form mx-auto flex w-full max-w-[1180px] min-w-0 flex-col gap-6">
|
||||
<div class="application-settings-form mx-auto flex w-full max-w-none min-w-0 flex-col gap-6">
|
||||
{{-- One bar for the whole page. Three stacked bars made Save run
|
||||
submitResend(), which required an API key even when Resend was off. --}}
|
||||
<x-unsaved-bar action="submit"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</x-slot>
|
||||
|
||||
<x-settings.layout>
|
||||
<div class="application-settings-form mx-auto w-full max-w-[1180px] min-w-0" x-data="{
|
||||
<div class="application-settings-form mx-auto w-full max-w-none min-w-0" x-data="{
|
||||
activeTab: ['executions', 'scheduler-runs', 'skipped-jobs'].includes(location.hash.slice(1))
|
||||
? location.hash.slice(1)
|
||||
: 'executions',
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@
|
|||
:mobileTitleOnly="true" />
|
||||
|
||||
@if ($showSettingsSidebar)
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="GitHub App settings"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
:mobileTitleOnly="true" />
|
||||
|
||||
@if ($showSettingsSidebar)
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-[1180px] lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-10">
|
||||
<section class="application-settings-workspace mt-4 w-full max-w-none lg:mt-0">
|
||||
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
|
||||
<aside class="application-settings-navigation min-w-0 xl:self-start">
|
||||
<nav aria-label="S3 storage settings"
|
||||
class="grid grid-cols-2 gap-0.5 border-y border-neutral-200 py-3 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-1 xl:border-y-0 xl:py-0 dark:border-white/[0.06]">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="application-settings-form w-full max-w-[1180px]">
|
||||
<div class="application-settings-form w-full max-w-none">
|
||||
<x-slot:title>
|
||||
Subscribe | Coolify
|
||||
</x-slot>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="application-settings-form w-full max-w-[1180px]">
|
||||
<div class="application-settings-form w-full max-w-none">
|
||||
<x-slot:title>
|
||||
Subscription | Coolify
|
||||
</x-slot>
|
||||
|
|
|
|||
|
|
@ -57,3 +57,16 @@
|
|||
->toContain("'database' => route('project.database.configuration'")
|
||||
->toContain("'service' => route('project.service.configuration'");
|
||||
});
|
||||
|
||||
test('breadcrumb switchers let users search their items', function () {
|
||||
$switcher = file_get_contents(resource_path('views/components/breadcrumb-switcher.blade.php'));
|
||||
|
||||
expect($switcher)
|
||||
->toContain('x-model.debounce.150ms="search"')
|
||||
->toContain('type="search"')
|
||||
->toContain('placeholder="Search {{ strtolower($title) }}"')
|
||||
->toContain('class="searchable-listbox-search"')
|
||||
->toContain('class="searchable-listbox-search-input"')
|
||||
->toContain('<x-reicon name="search"')
|
||||
->toContain('.includes(search.toLowerCase())');
|
||||
});
|
||||
|
|
|
|||
16
tests/Feature/FullWidthResourceLayoutTest.php
Normal file
16
tests/Feature/FullWidthResourceLayoutTest.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
test('the application shell and resource workspaces use the full available width', function () {
|
||||
$appLayout = file_get_contents(resource_path('views/layouts/app.blade.php'));
|
||||
$applicationConfiguration = file_get_contents(resource_path('views/livewire/project/application/configuration.blade.php'));
|
||||
$serverConfiguration = file_get_contents(resource_path('views/livewire/server/show.blade.php'));
|
||||
|
||||
expect($appLayout)
|
||||
->toContain("pageWidth === 'centered' ? 'mx-auto max-w-[1400px]' : 'max-w-none'")
|
||||
->and($applicationConfiguration)
|
||||
->not->toContain('max-w-[1180px]')
|
||||
->toContain('xl:gap-8')
|
||||
->and($serverConfiguration)
|
||||
->not->toContain('max-w-[1180px]')
|
||||
->toContain('xl:gap-8');
|
||||
});
|
||||
|
|
@ -34,23 +34,23 @@
|
|||
->not->toContain('<x-status-badge status="Enabled" type="success" />');
|
||||
});
|
||||
|
||||
it('keeps color theme preferences on the profile appearance view without page width or density controls', function () {
|
||||
it('offers full and centered page width preferences on the profile appearance view', function () {
|
||||
$appearanceView = file_get_contents(resource_path('views/livewire/profile/appearance.blade.php'));
|
||||
$appLayout = file_get_contents(resource_path('views/layouts/app.blade.php'));
|
||||
|
||||
expect($appearanceView)
|
||||
->not->toContain('<x-profile.navbar />')
|
||||
->toContain('Color theme')
|
||||
->toContain("setTheme('{{ \$option['value'] }}')")
|
||||
->toContain("['value' => 'light'")
|
||||
->toContain("['value' => 'system'")
|
||||
->toContain('to-[#050505]')
|
||||
->toContain("['value' => 'dark'")
|
||||
->not->toContain('Page width')
|
||||
->toContain('Page width')
|
||||
->toContain("pageWidth: localStorage.getItem('pageWidth') || 'full'")
|
||||
->toContain("['value' => 'full'")
|
||||
->toContain("['value' => 'centered'")
|
||||
->toContain("@click=\"setWidth('{{ \$option['value'] }}')\"")
|
||||
->toContain("localStorage.setItem('pageWidth', width)")
|
||||
->not->toContain('Interface density')
|
||||
->not->toContain('setWidth(')
|
||||
->not->toContain('setZoom(')
|
||||
->not->toContain('pageWidth')
|
||||
->not->toContain("localStorage.getItem('zoom')")
|
||||
->not->toContain("localStorage.setItem('pageWidth'")
|
||||
->not->toContain("localStorage.setItem('zoom'");
|
||||
->and($appLayout)
|
||||
->toContain("pageWidth: localStorage.getItem('pageWidth') || 'full'")
|
||||
->toContain('@page-width-changed.window="pageWidth = $event.detail"')
|
||||
->toContain("pageWidth === 'centered' ? 'mx-auto max-w-[1400px]' : 'max-w-none'");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,25 +7,25 @@
|
|||
|
||||
expect($html)
|
||||
->toContain('aria-label="Items per page"')
|
||||
->toContain('aria-haspopup="listbox"')
|
||||
->toContain('role="listbox"')
|
||||
->toContain("\$wire.set('perPage'")
|
||||
->toContain('h-7!')
|
||||
->toContain('w-12!')
|
||||
->toContain('opacity-0')
|
||||
->toContain('selectedPageSize')
|
||||
->toContain('border-0')
|
||||
->toContain('text-[11px]!')
|
||||
->toContain('mb-0!')
|
||||
->not->toContain('<select')
|
||||
->toContain("localStorage.getItem('tests.page-size')")
|
||||
->toContain("localStorage.setItem('tests.page-size'")
|
||||
->toContain('value="10"')
|
||||
->toContain('value="25"')
|
||||
->toContain('value="50"')
|
||||
->toContain('value="100"');
|
||||
->toContain('applyPageSize(10)')
|
||||
->toContain('applyPageSize(25)')
|
||||
->toContain('applyPageSize(50)')
|
||||
->toContain('applyPageSize(100)')
|
||||
->not->toContain('>Rows</span>');
|
||||
expect($html)
|
||||
->toContain('value="custom"')
|
||||
->toContain('data-custom-page-size')
|
||||
->toContain('customOption?.remove()')
|
||||
->not->toContain('<option value="" disabled selected>')
|
||||
->toContain('Custom…')
|
||||
->toContain('min="1"')
|
||||
->toContain('max="100"');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -65,3 +65,17 @@
|
|||
->toContain('hover:bg-neutral-200 hover:text-neutral-950')
|
||||
->not->toContain("route('profile.appearance')");
|
||||
});
|
||||
|
||||
it('offers page width controls inside the appearance menu', function () {
|
||||
$menu = file_get_contents(resource_path('views/components/top-user-menu.blade.php'));
|
||||
|
||||
expect($menu)
|
||||
->toContain("pageWidth: localStorage.getItem('pageWidth') || 'full'")
|
||||
->toContain("['value' => 'full', 'label' => 'Full width']")
|
||||
->toContain("['value' => 'centered', 'label' => 'Centered']")
|
||||
->toContain("@click=\"setWidth('{{ \$option['value'] }}')\"")
|
||||
->toContain('Full width')
|
||||
->toContain('Centered')
|
||||
->toContain("localStorage.setItem('pageWidth', width)")
|
||||
->toContain("new CustomEvent('page-width-changed', { detail: width })");
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue