feat(ui): WCAG contrast, neutral oklch surface system, and mobile nav overhaul

Design tokens
- Fix WCAG AA text failures: darken light muted text and lighten dark
  tertiary text so 13-14px copy clears 4.5:1 on every surface.
- Rebuild the dark surface ladder in correct values (oklch compresses to
  near-black below ~15%), giving visible steps: content, chrome, cards.
- Establish a 3-layer shell (deep content, lighter sidebar/topbar chrome,
  lifted cards) with crisp hairline rings and a restrained card shadow.
- Unify every surface to one neutral temperature (pure gray); neutralize
  the cool-tinted sidebar text and legacy surface tokens.
- Convert all color tokens to oklch (neutrals + brand).
- Unify inputs to the recessed token; fix invisible dark placeholders.
- One shared --shadow-dropdown for all menus/listboxes/command palette.

Settings sidebar
- Sticky contained-card rail with subtle scrollbar; collapsible sub-section
  groups (active open by default), cross-page section links.
- Mobile: collapsible disclosure with animated open, outside/Escape dismiss,
  press feedback, and reduced-motion support.

Mobile
- Consolidate the resource header (title + status + links on one row).
- Tighten settings-page vertical rhythm.
- Rebuild the main sidebar as an animated shadcn-style sheet (slide/fade,
  Escape, scroll lock, in-panel close, close-on-navigate).

Fixes
- #11532: selected server invisible in the light-mode terminal toolbar.

Docs: update DESIGN.md tokens, shell layering, and temperature rules.
This commit is contained in:
Aditya Tripathi 2026-09-07 02:35:56 +00:00 committed by Andras Bacsai
parent ba30c64d7d
commit d91d2fa35d
59 changed files with 467 additions and 272 deletions

View file

@ -34,7 +34,9 @@ ## 1. Visual direction
- near-neutral layered surfaces instead of large bordered boxes;
- 1314px UI typography and 32px controls;
- hairline rings instead of heavy borders;
- crisp hairline rings plus a restrained card lift (single 1px ring +
`0 1px 2px rgb(0 0 0 / 0.05)`) so cards and tables separate from the canvas,
never heavy borders or a strong floating shadow;
- full-width data tables for dense collections;
- outline Reicon glyphs through `<x-reicon>`;
- the Coolify purple brand accent in light mode;
@ -89,14 +91,14 @@ ## 3. Tokens and color behavior
| Token | Light | Dark | Use |
|---|---|---|---|
| `--coollabs-canvas` | near white | 10% neutral | page canvas |
| `--coollabs-canvas` | 97% off-white | 10% neutral | page canvas (kept below card fills so cards lift) |
| `--coollabs-elevated` | 98% neutral | 15% neutral | shells and card headers |
| `--coollabs-base` | white | 17% neutral | nested card bodies |
| `--coollabs-recessed` | 96% neutral | 20% neutral | inputs and listboxes |
| `--coollabs-fill` | 92.2% neutral | 26.9% neutral | dividers and passive fills |
| `--coollabs-line` | translucent dark | 32% neutral | control borders |
| `--coollabs-hairline` | 93.5% neutral | 26.9% neutral | shell rings |
| `--coollabs-subtle` | 55.6% neutral | 70.8% neutral | labels and muted titles |
| `--coollabs-hairline` | 85.5% neutral | 32% neutral | shell rings (crisp enough to read as a card edge, ~1.5:1) |
| `--coollabs-subtle` | 50% neutral | 70.8% neutral | labels and muted titles (light darkened for WCAG AA 4.5:1) |
Accent behavior is intentionally theme-aware:
@ -116,6 +118,38 @@ ## 3. Tokens and color behavior
The filled top-level action/tab treatment uses the same palette at a restrained
opacity rather than a fully saturated fill.
### Shell layering
The app shell is three distinct surface layers, not one flat color. Chrome
lifts, content is the base, cards lift off the content:
- **Content canvas** is the base layer: `bg-app` in dark (deepest,
`--color-app` `#0a0a0b`), `bg-gray-50` in light. The `<main>` content area
and page body use it.
- **Sidebar and topbar chrome** use `bg-panel` in dark (`--color-panel`
`#141418`, a clear step lighter than the content canvas) and `bg-white` in
light, so the chrome reads as a separate panel from the content.
Dark surface tokens are hex, not oklch. oklch lightness compresses toward pure
black below ~15% (oklch(10%) renders as sRGB 3, oklch(15%) as sRGB 11), so oklch
values there give no visible step between layers. The dark ladder is
`--color-app` 10, `--coollabs-elevated` 22, `--coollabs-base` 28,
`--coollabs-recessed` 34 (sRGB), which reads as distinct surfaces.
Temperature: every panel is **pure neutral gray** (r=g=b), one consistent
temperature across the sidebar, tables, cards, inputs, dividers, borders, and
text, in both modes. Do not give one surface a cool (blue) or warm cast while
the others stay neutral. The light page canvas uses `bg-neutral-50` (not
`bg-gray-50`, which is faintly cool) so it matches the neutral cards and chrome.
The only intentional color is the purple/yellow brand accent.
- **Cards, tables, and collection tiles** lift off the content canvas with
`dark:bg-white/[0.05]` plus the crisp `--coollabs-hairline` ring; in light
they are `bg-white` with the ring and the restrained card lift.
Do not paint the content area with the same `bg-panel` as the sidebar, and do
not drop card fills below `dark:bg-white/[0.05]`; both make surfaces read as one
color. Row-hover states keep the lighter `dark:hover:bg-white/[0.025]`.
---
## 4. Page shells and navigation
@ -419,6 +453,12 @@ ### Dropdowns
the option content left-aligned and size the panel to its content or trigger;
do not create an unnecessarily wide menu.
Every dropdown, menu, listbox panel, and the command palette uses the shared
`--shadow-dropdown` token (`0 4px 12px rgb(0 0 0 / 0.12), 0 2px 4px
rgb(0 0 0 / 0.08)`) for a restrained, consistent lift. Do not hand-roll a
heavier `shadow-lg` / `0 18px 50px` / `0.45`-alpha drop shadow on a menu.
Reserve the stronger `--shadow-modal` for actual modals, dialogs, and toasts.
Toolbar filter and sort buttons keep static labels (`Filter`, `Sort`). The
selected option is indicated inside the menu, not repeated on the trigger.

View file

@ -20,51 +20,63 @@ @theme {
--font-geist-sans: 'Geist Sans', Inter, sans-serif;
--font-logs: 'Geist Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
--color-base: #101010;
--color-warning: #fcd452;
--color-warning-50: #fefce8;
--color-warning-100: #fef9c3;
--color-warning-200: #fef08a;
--color-warning-300: #fde047;
--color-warning-400: #fcd452;
--color-warning-500: #facc15;
--color-warning-600: #ca8a04;
--color-warning-700: #a16207;
--color-warning-800: #854d0e;
--color-warning-900: #713f12;
--color-success: #22C55E;
--color-error: #dc2626;
--color-coollabs-50: #f5f0ff;
--color-coollabs: #6b16ed;
--color-coollabs-100: #7317ff;
--color-coollabs-200: #5a12c7;
--color-coollabs-300: #4a0fa3;
--color-coolgray-100: #181818;
--color-coolgray-200: #202020;
--color-coolgray-300: #242424;
--color-coolgray-400: #282828;
--color-coolgray-500: #323232;
--color-base: oklch(17.3% 0 0);
--color-warning: oklch(88.13% 0.1507 91.7);
--color-warning-50: oklch(98.73% 0.0262 102.21);
--color-warning-100: oklch(97.29% 0.0693 103.19);
--color-warning-200: oklch(94.51% 0.1243 101.54);
--color-warning-300: oklch(90.52% 0.1657 98.11);
--color-warning-400: oklch(88.13% 0.1507 91.7);
--color-warning-500: oklch(86.06% 0.1731 91.94);
--color-warning-600: oklch(68.06% 0.1423 75.83);
--color-warning-700: oklch(55.38% 0.1207 66.44);
--color-warning-800: oklch(47.62% 0.1034 61.91);
--color-warning-900: oklch(42.1% 0.0897 57.71);
--color-success: oklch(72.27% 0.192 149.58);
--color-error: oklch(57.71% 0.2152 27.33);
--color-coollabs-50: oklch(96.33% 0.0206 301.15);
--color-coollabs: oklch(49.65% 0.2709 289.33);
--color-coollabs-100: oklch(52.34% 0.287 289.16);
--color-coollabs-200: oklch(43.76% 0.2369 289.82);
--color-coollabs-300: oklch(38.04% 0.2031 290.47);
--color-coolgray-100: oklch(20.9% 0 0);
--color-coolgray-200: oklch(24.35% 0 0);
--color-coolgray-300: oklch(26.03% 0 0);
--color-coolgray-400: oklch(27.68% 0 0);
--color-coolgray-500: oklch(31.71% 0 0);
/* Graphite design language (ported from ref/frontend). Layered neutral
surfaces + translucent hairlines. See DESIGN.md. */
--color-app: #0c0c0d;
/* Canvas: neutral near-black (oklch), not pure black */
--color-panel: oklch(10% 0 0);
--color-surface: #161618;
--color-raised: #1c1c1e;
--color-selected: #26262a;
--color-fg: #f2f2f2;
--color-fg-dim: #b4b4b8;
--color-fg-faint: #6e6e74;
--color-accent: #6b16ed;
--color-accent-foreground: #ffffff;
--color-hairline: rgba(255, 255, 255, 0.08);
--color-nav-text: #525252;
--color-nav-muted: #666666;
--color-nav-active: #171717;
--color-log: #0d0d0d;
/* Content canvas: the darkest shell layer (sRGB ~10). Hex, not oklch:
oklch lightness compresses to near-black below ~15%, so oklch(7.5%)
renders as sRGB 1 with no visible step. */
--color-app: oklch(14.48% 0 0);
/* Sidebar + topbar chrome (sRGB ~20): a clear step lighter than the content
canvas so the shell chrome separates from the content area. */
--color-panel: oklch(19.13% 0 0);
/* Pure neutral (r=g=b). Were cool-tinted (#161618/#1c1c1e/#26262a, b>r),
which clashed with the neutral panel ladder. */
--color-surface: oklch(20.02% 0 0);
--color-raised: oklch(22.64% 0 0);
--color-selected: oklch(26.86% 0 0);
--color-fg: oklch(96.12% 0 0);
--color-fg-dim: oklch(76.99% 0 0);
/* Tertiary text. Raised from #6e6e74 (3.78:1 on base, failed WCAG AA)
to #7e7e84 so 13-14px text clears 4.5:1 on the dark surface ladder. */
--color-fg-faint: oklch(59.31% 0 0);
--color-accent: oklch(49.65% 0.2709 289.33);
--color-accent-foreground: oklch(100.0% 0 0);
--color-hairline: oklch(100.0% 0 0 / 0.08);
--color-nav-text: oklch(43.86% 0 0);
--color-nav-muted: oklch(51.03% 0 0);
--color-nav-active: oklch(20.46% 0 0);
--color-log: oklch(15.91% 0 0);
--shadow-modal: 0 24px 64px rgba(0, 0, 0, 0.55), 0 4px 16px rgba(0, 0, 0, 0.4);
/* One restrained lift shared by every dropdown/menu/listbox panel and the
command palette. Lighter and consistent, replacing the old scattered
0.45 / 0.35 / shadow-lg / shadow-sm mix. Modals keep --shadow-modal. */
--shadow-dropdown: 0 4px 12px rgb(0 0 0 / 0.12), 0 2px 4px rgb(0 0 0 / 0.08);
}
/*
@ -258,7 +270,7 @@ @layer components {
*/
html,
body {
@apply w-full min-h-full bg-gray-50 dark:bg-app dark:text-fg-dim;
@apply w-full min-h-full bg-neutral-50 dark:bg-app dark:text-fg-dim;
}
body {
@ -505,8 +517,8 @@ .terminal-fullscreen-shell::before {
.application-console-shell[data-console-theme="system"],
.terminal-fullscreen-shell[data-console-theme="system"] {
--console-theme-background: #fff;
--console-theme-border: #d4d4d8;
--console-theme-background: oklch(100.0% 0 0);
--console-theme-border: oklch(87.11% 0.0055 286.29);
--console-theme-opacity: 1;
}
@ -517,13 +529,20 @@ html:not(.dark) .application-console-shell[data-console-theme="system"] .applica
backdrop-filter: none;
}
html:not(.dark) .application-console-shell[data-console-theme="system"] .application-console-header [class*="text-white"] {
html:not(.dark) .application-console-shell[data-console-theme="system"] .application-console-header [class*="text-white"],
/* Session toolbar (selected-target trigger + label) sits over the white
system console in light mode. Without this its text-white/* stayed white on
white and the selected server was invisible (issue #11532). */
html:not(.dark) .application-console-shell[data-console-theme="system"] .terminal-session-toolbar[class*="text-white"],
html:not(.dark) .application-console-shell[data-console-theme="system"] .terminal-session-toolbar [class*="text-white"],
html:not(.dark) .terminal-fullscreen-shell[data-console-theme="system"] .terminal-session-toolbar[class*="text-white"],
html:not(.dark) .terminal-fullscreen-shell[data-console-theme="system"] .terminal-session-toolbar [class*="text-white"] {
color: #52525b !important;
}
html.dark .application-console-shell[data-console-theme="system"],
html.dark .terminal-fullscreen-shell[data-console-theme="system"] {
--console-theme-background: #121214;
--console-theme-background: oklch(18.31% 0.004 285.99);
--console-theme-border: rgb(255 255 255 / 0.08);
}
@ -851,7 +870,7 @@ html:not(.dark) .application-console-shell[data-console-theme="system"] .termina
color: #52525b;
background: #fff;
border-color: #d4d4d8;
box-shadow: 0 18px 50px rgb(0 0 0 / 0.18);
box-shadow: var(--shadow-dropdown);
}
html:not(.dark) .application-console-shell[data-console-theme="system"] .terminal-target-picker [class*="text-white"] {
@ -924,37 +943,53 @@ .terminal-fullscreen-btn:hover {
* utility classes placed in the card markup.
*/
:root {
--coollabs-canvas: oklch(98.75% 0 0);
/* Page canvas is a faint off-white so white/elevated cards lift off it
(shadcn pattern), instead of card and page reading as one flat color. */
--coollabs-canvas: oklch(97% 0 0);
--coollabs-elevated: oklch(98% 0 0);
--coollabs-recessed: oklch(96% 0 0);
--coollabs-base: #ffffff;
--coollabs-base: oklch(100.0% 0 0);
--coollabs-fill: oklch(92.2% 0 0);
--coollabs-line: oklch(14.5% 0 0 / 0.1);
--coollabs-hairline: oklch(93.5% 0 0);
--coollabs-subtle: oklch(55.6% 0 0);
/* Card/table edge ring. Crisped from 93.5% (1.17:1 on canvas, invisible)
to 85.5% (1.51:1) so surfaces read as bordered cards, not flat fills. */
--coollabs-hairline: oklch(85.5% 0 0);
/* Muted labels/titles. Darkened from 55.6% (failed WCAG AA on elevated
4.46, recessed 4.24, fill 3.76) to 50% so muted text clears 4.5:1 on
every light surface above white. Dark stays 70.8% (already passes). */
--coollabs-subtle: oklch(50% 0 0);
}
.dark {
--color-accent: #fcd452;
--coollabs-canvas: oklch(10% 0 0);
/* elevated (card shells/headers) and recessed (input fills) sit a touch
above the canvas so they read lighter than near-black */
--coollabs-elevated: oklch(15% 0 0);
--coollabs-recessed: oklch(20% 0 0);
--coollabs-base: oklch(17% 0 0);
--coollabs-fill: oklch(26.9% 0 0);
--color-accent: oklch(88.13% 0.1507 91.7);
/* Dark surface ladder in hex (sRGB), not oklch: oklch lightness compresses
to near-black below ~15%, so oklch(15%) rendered as sRGB 11 and cards
could not lift off the content canvas (sRGB 10). These give clear,
visible steps: content 10 -> elevated 22 -> base 28 -> recessed 34.
Pure neutral (r=g=b), matching the neutral borders/text and the light
ladder, so every panel shares one temperature (no blue cast). */
--coollabs-canvas: oklch(14.48% 0 0);
--coollabs-elevated: oklch(20.02% 0 0);
--coollabs-recessed: oklch(25.2% 0 0);
--coollabs-base: oklch(22.64% 0 0);
--coollabs-fill: oklch(29.31% 0 0);
--coollabs-line: oklch(32% 0 0);
--coollabs-hairline: oklch(26.9% 0 0);
/* Crisped from 26.9% (1.36:1 on canvas) to 32% (1.63:1) so dark cards
and tables show a visible edge instead of blending into the canvas. */
--coollabs-hairline: oklch(32% 0 0);
--coollabs-subtle: oklch(70.8% 0 0);
--color-nav-text: #a8a8b0;
--color-nav-muted: #7a7a84;
--color-nav-active: #f2f2f2;
/* Neutral (was #a8a8b0 / #7a7a84, both cool-tinted). Sidebar text now shares
the same neutral temperature as the content text, so the sidebar no longer
reads cooler than the panels/cards. */
--color-nav-text: oklch(73.8% 0 0);
--color-nav-muted: oklch(58.97% 0 0);
--color-nav-active: oklch(96.12% 0 0);
}
/* Theme surfaces are derived from one brand color. Changing
--theme-base-color is enough to generate a complete dark surface ladder. */
html[data-theme="custom"] {
--theme-base-color: #6b16ed;
--theme-base-color: oklch(49.65% 0.2709 289.33);
--theme-bright-color: color-mix(in srgb, var(--theme-base-color) 85%, white);
--theme-scrollbar-thumb: color-mix(in srgb, var(--theme-bright-color) 70%, var(--theme-accent-foreground));
--theme-border-color: color-mix(in oklab, var(--theme-base-color) 42%, #52525b);
@ -985,14 +1020,14 @@ html[data-theme="custom"] {
--coollabs-fill: color-mix(in oklab, var(--theme-base-color) 32%, #18181a);
--coollabs-line: var(--theme-border-color);
--coollabs-hairline: color-mix(in srgb, var(--theme-border-color) 55%, var(--color-panel));
--color-nav-text: #e4dfea;
--color-nav-muted: #d8d2df;
--color-nav-active: #ffffff;
--color-nav-text: oklch(91.08% 0.0157 306.4);
--color-nav-muted: oklch(87.24% 0.0188 306.63);
--color-nav-active: oklch(100.0% 0 0);
--color-log: color-mix(in oklab, var(--theme-base-color) 20%, #080809);
--color-log-toolbar: color-mix(in oklab, var(--theme-base-color) 26%, #101011);
--color-fg-dim: #e4dfea;
--color-fg-faint: #d8d2df;
--coollabs-subtle: #d8d2df;
--color-fg-dim: oklch(91.08% 0.0157 306.4);
--color-fg-faint: oklch(87.24% 0.0188 306.63);
--coollabs-subtle: oklch(87.24% 0.0188 306.63);
}
html[data-theme="custom"] .control-selected,
@ -1349,7 +1384,9 @@ .application-settings-section {
border-radius: 8px;
border: none;
background: var(--coollabs-elevated);
box-shadow: 0 0 0 1px var(--coollabs-hairline);
/* crisp ring + a restrained lift so the card separates from the canvas
(shadcn-style), not a heavy floating shadow */
box-shadow: 0 0 0 1px var(--coollabs-hairline), 0 1px 2px 0 rgb(0 0 0 / 0.05);
/* keep anchored scrolls (scrollIntoView) clear of the fixed topbar + layer-2 nav */
scroll-margin-top: 7rem;
}
@ -1471,16 +1508,49 @@ .server-settings-workspace > :not(.application-settings-navigation) {
@media (min-width: 1280px) {
.application-settings-navigation {
position: sticky;
top: calc(3rem + 1.75rem);
top: calc(3rem + 1rem);
align-self: start;
max-height: calc(100dvh - 5.5rem);
padding-right: 0.375rem;
max-height: calc(100dvh - 5rem);
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
/* Thin, subtle overlay scrollbar so it does not fight the card's rounded
edge. Gutter stays stable so content does not shift when it appears. */
scrollbar-width: thin;
scrollbar-color: var(--coollabs-fill) transparent;
scrollbar-gutter: stable;
/* Contained card: a distinct elevated surface with a hairline ring and a
restrained lift, so the settings nav reads as a structured panel that
floats above the content canvas instead of loose links on the page. */
padding: 0.5rem;
background: var(--coollabs-elevated);
border: 1px solid var(--coollabs-hairline);
border-radius: 12px;
box-shadow: 0 1px 2px rgb(0 0 0 / 0.05);
}
.application-settings-navigation::-webkit-scrollbar {
width: 6px;
}
.application-settings-navigation::-webkit-scrollbar-track {
background: transparent;
}
.application-settings-navigation::-webkit-scrollbar-thumb {
border-radius: 9999px;
background: var(--coollabs-fill);
}
.application-settings-navigation::-webkit-scrollbar-thumb:hover {
background: var(--coollabs-line);
}
/* Resource settings rail: pinned as a stacked second sidebar, flush to the
main sidebar's right edge (left tracks its collapsed width via --rail-left).
A subtle step lighter than the main sidebar chrome, with a hairline divider,
so the two rails read as a cohesive stacked pair and the content is the
distinct surface to their right. */
/* Resource pages have a second fixed header row below the main header. */
.application-settings-workspace > .application-settings-navigation {
top: 4rem;
@ -1494,6 +1564,17 @@ @media (min-width: 1280px) {
}
}
/* Honor reduced-motion for the settings nav disclosure/accordion and the mobile
sidebar sheet: keep open/close functional but drop the height/slide/fade. */
@media (prefers-reduced-motion: reduce) {
.application-settings-navigation,
.application-settings-navigation *,
.mobile-sidebar-sheet * {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
/* Field labels */
.application-settings-workspace label,
.application-settings-form label {
@ -1603,7 +1684,7 @@ .resource-heading-tabs::-webkit-scrollbar {
* Circular chevrons sit over gradient fades when more tabs are off-screen.
*/
.resource-heading-tabs-scroller {
--resource-heading-tabs-fade: #f5f5f5; /* neutral-100, matches pill track */
--resource-heading-tabs-fade: oklch(97.02% 0 0); /* neutral-100, matches pill track */
}
.dark .resource-heading-tabs-scroller {
@ -1944,7 +2025,7 @@ .listbox-panel {
border-radius: 10px;
border: 1px solid var(--coollabs-line);
background: var(--coollabs-recessed);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
box-shadow: var(--shadow-dropdown);
}
@media (max-width: 767px) {

View file

@ -59,7 +59,7 @@ @utility input-focus {
/* input, select before */
@utility input-select {
@apply block h-9 px-3 py-1.5 w-full text-sm text-black rounded-md border border-neutral-200 bg-white dark:bg-surface dark:text-fg dark:border-white/[0.08] transition-colors disabled:bg-neutral-100 disabled:text-neutral-400 dark:disabled:bg-white/[0.03] dark:disabled:text-fg-faint;
@apply block h-9 px-3 py-1.5 w-full text-sm text-black rounded-md border border-neutral-200 bg-[var(--coollabs-recessed)] dark:text-fg dark:border-white/[0.08] transition-colors disabled:bg-neutral-100 disabled:text-neutral-400 dark:disabled:bg-white/[0.03] dark:disabled:text-fg-faint;
box-shadow: none;
&:where(.dark, .dark *) {
@ -77,7 +77,7 @@ @utility input-select {
/* Readonly */
@utility input {
@apply dark:read-only:text-neutral-500 dark:read-only:bg-coolgray-100/40 placeholder:text-neutral-300 dark:placeholder:text-neutral-700 read-only:text-neutral-500 read-only:bg-neutral-200;
@apply dark:read-only:text-neutral-500 dark:read-only:bg-coolgray-100/40 placeholder:text-neutral-400 dark:placeholder:text-neutral-500 read-only:text-neutral-500 read-only:bg-neutral-200;
@apply input-select;
@apply focus-visible:outline-none;

View file

@ -124,3 +124,16 @@ window.scrollToSettingsSection = function scrollToSettingsSection(id) {
rafId = window.requestAnimationFrame(tick);
};
// When a settings sub-section link navigates across pages (href="route#section-id"),
// scroll to that section once the destination page has rendered.
function scrollToHashSettingsSection() {
const hash = window.location.hash;
if (!hash || hash.length < 2) {
return;
}
const id = decodeURIComponent(hash.slice(1));
window.requestAnimationFrame(() => window.scrollToSettingsSection?.(id));
}
document.addEventListener('livewire:navigated', scrollToHashSettingsSection);
document.addEventListener('DOMContentLoaded', scrollToHashSettingsSection);

View file

@ -238,52 +238,98 @@
];
@endphp
@php
$activeMenuLabel = collect($groupedMenuItems)->flatMap(fn ($items) => $items)->firstWhere('active', true)['label'] ?? 'Settings';
@endphp
<aside @class([
'application-settings-navigation min-w-0 xl:self-start',
'is-flush' => $flush,
])>
<nav aria-label="Configuration sections"
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]">
])
x-data="{
menuOpen: false,
desktop: window.matchMedia('(min-width: 1280px)').matches,
init() {
const mq = window.matchMedia('(min-width: 1280px)');
mq.addEventListener('change', (e) => { this.desktop = e.matches; if (e.matches) { this.menuOpen = false; } });
},
}"
x-on:click.outside="menuOpen = false"
x-on:keydown.escape.window="menuOpen = false">
{{-- Mobile disclosure: tap to reveal the full grouped nav; hidden at xl (the pinned rail). --}}
<button type="button" x-show="!desktop" x-cloak x-on:click="menuOpen = !menuOpen"
:aria-expanded="menuOpen" aria-label="Configuration menu"
:class="menuOpen && 'ring-1 ring-black/10 dark:ring-white/15'"
class="flex h-10 w-full items-center justify-between gap-2 rounded-xl border border-neutral-200 bg-white px-3 text-[13px] font-medium text-black transition-transform duration-100 ease-out hover:bg-neutral-50 active:scale-[0.985] dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg dark:hover:bg-white/[0.08]">
<span class="flex min-w-0 items-center gap-2">
<x-reicon name="settings" class="size-4 shrink-0 text-nav-muted" />
<span class="truncate">{{ $activeMenuLabel }}</span>
</span>
<svg class="size-3.5 shrink-0 text-nav-muted transition-transform duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]"
:class="menuOpen && 'rotate-180'" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="m3.5 4.75 2.5 2.5 2.5-2.5" stroke="currentColor" stroke-width="1.25"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</button>
<nav aria-label="Configuration sections" x-show="desktop || menuOpen" x-collapse.duration.200ms x-cloak
class="mt-2 flex flex-col gap-0.5 rounded-xl border border-neutral-200 bg-white p-2 shadow-[var(--shadow-dropdown)] dark:border-white/[0.08] dark:bg-white/[0.03] xl:mt-0 xl:rounded-none xl:border-0 xl:bg-transparent xl:p-0 xl:shadow-none xl:dark:bg-transparent">
@foreach ($groupedMenuItems as $groupLabel => $groupItems)
@unless ($loop->first)
<div class="hidden xl:block my-2 border-t border-neutral-200 dark:border-white/[0.06]" aria-hidden="true"></div>
<div class="my-2 border-t border-neutral-200 dark:border-white/[0.06]" aria-hidden="true"></div>
@endunless
<div class="nav-section hidden xl:block">{{ $groupLabel }}</div>
<div class="nav-section">{{ $groupLabel }}</div>
@foreach ($groupItems as $menuItem)
<a wire:key="application-settings-link-{{ str($menuItem['label'])->slug() }}"
@class([
'menu-item',
'menu-item-active' => $menuItem['active'],
])
@if ($menuItem['navigate'] ?? true) {{ wireNavigate() }} @endif
href="{{ route($menuItem['route'], $applicationRouteParameters) }}">
<x-reicon :name="$menuIcons[$menuItem['label']] ?? 'settings'" class="menu-item-icon" />
<span class="menu-item-label">{{ $menuItem['label'] }}</span>
@if ($menuItem['badge'] ?? false)
<span class="shrink-0">
<livewire:project.application.server-status-badge :application="$application"
:key="'application-server-status-'.$application->uuid" />
</span>
@php $sections = $pageSections[$menuItem['route']] ?? []; @endphp
<div wire:key="application-settings-group-{{ str($menuItem['label'])->slug() }}"
@if (filled($sections)) x-data="{ open: @js($menuItem['active']), activeSection: '' }" @endif
class="relative">
<a wire:key="application-settings-link-{{ str($menuItem['label'])->slug() }}"
@class([
'menu-item',
'menu-item-active' => $menuItem['active'],
'pr-9' => filled($sections),
])
@if ($menuItem['navigate'] ?? true) {{ wireNavigate() }} @endif
href="{{ route($menuItem['route'], $applicationRouteParameters) }}"
x-on:click="menuOpen = false">
<x-reicon :name="$menuIcons[$menuItem['label']] ?? 'settings'" class="menu-item-icon" />
<span class="menu-item-label">{{ $menuItem['label'] }}</span>
@if ($menuItem['badge'] ?? false)
<span class="shrink-0">
<livewire:project.application.server-status-badge :application="$application"
:key="'application-server-status-'.$application->uuid" />
</span>
@endif
</a>
@if (filled($sections))
{{-- Expand/collapse the page's sub-sections. Active page opens by
default; the label still navigates, the chevron only toggles. --}}
<button type="button"
class="absolute right-1 top-1 flex size-6 items-center justify-center rounded-md text-nav-muted transition-colors hover:bg-black/[0.04] hover:text-nav-active dark:hover:bg-white/[0.06]"
x-on:click.stop.prevent="open = !open" :aria-expanded="open"
aria-label="Toggle {{ $menuItem['label'] }} sections">
<svg class="size-3.5 transition-transform duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]"
:class="open && 'rotate-90'" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="m4.5 3 3 3-3 3" stroke="currentColor" stroke-width="1.25"
stroke-linecap="round" stroke-linejoin="round" />
</svg>
</button>
<div>
<div x-show="open" x-collapse x-cloak
class="nav-children flex flex-col gap-0.5 py-1">
@foreach ($sections as $section)
<a class="menu-subitem"
:class="activeSection === '{{ $section['id'] }}' && 'menu-subitem-active'"
href="{{ route($menuItem['route'], $applicationRouteParameters) }}#{{ $section['id'] }}"
{{ wireNavigate() }}
x-on:click="menuOpen = false; if (document.getElementById('{{ $section['id'] }}')) { $event.preventDefault(); activeSection = '{{ $section['id'] }}'; history.replaceState(null, '', '#{{ $section['id'] }}'); window.scrollToSettingsSection?.('{{ $section['id'] }}'); }">
<span class="menu-item-label text-left">{{ $section['label'] }}</span>
</a>
@endforeach
</div>
</div>
@endif
</a>
@if ($menuItem['active'] && count($pageSections[$menuItem['route']] ?? []) >= 4)
<div class="nav-children hidden flex-col gap-0.5 py-1 xl:flex"
x-data="{
activeSection: '',
scrollToSection(id) {
this.activeSection = id;
window.scrollToSettingsSection?.(id);
},
}">
@foreach ($pageSections[$menuItem['route']] as $section)
<button type="button" class="menu-subitem"
:class="activeSection === '{{ $section['id'] }}' && 'menu-subitem-active'"
@click="scrollToSection('{{ $section['id'] }}')">
<span class="menu-item-label text-left">{{ $section['label'] }}</span>
</button>
@endforeach
</div>
@endif
</div>
@endforeach
@endforeach
</nav>

View file

@ -2,7 +2,7 @@
<div class="mx-auto mb-6 w-full max-w-3xl">
<div
class="grid grid-cols-3 overflow-hidden rounded-[10px] border border-neutral-200 bg-white dark:border-white/[0.08] dark:bg-white/[0.025]">
class="grid grid-cols-3 overflow-hidden rounded-[10px] border border-neutral-200 bg-white dark:border-white/[0.08] dark:bg-white/[0.05]">
@for ($i = 1; $i <= $totalSteps; $i++)
<div @class([
'flex min-h-10 items-center justify-center gap-2 border-r border-neutral-200 px-3 text-[11px] font-medium last:border-r-0 dark:border-white/[0.08]',

View file

@ -68,7 +68,7 @@
]) x-cloak>
<div @class([
'border border-neutral-300 bg-white p-1 dark:border-coolgray-300',
'shadow-sm dark:bg-coolgray-200' => ! $inline,
'shadow-[var(--shadow-dropdown)] dark:bg-coolgray-200' => ! $inline,
'border-0 bg-transparent shadow-none dark:border-0 dark:bg-transparent' => $inline,
$panelClass,
])>

View file

@ -91,7 +91,7 @@
x-transition:enter-start="opacity-0 scale-95" x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75" x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute z-20 top-full mt-1 w-56 -ml-2 bg-white dark:bg-coolgray-100 rounded-md shadow-lg py-1 border border-neutral-200 dark:border-coolgray-200 max-h-96 overflow-y-auto scrollbar">
class="absolute z-20 top-full mt-1 w-56 -ml-2 bg-white dark:bg-coolgray-100 rounded-md shadow-[var(--shadow-dropdown)] py-1 border border-neutral-200 dark:border-coolgray-200 max-h-96 overflow-y-auto scrollbar">
@foreach ($projects as $project)
<a href="{{ route('project.show', ['project_uuid' => $project->uuid]) }}" {{ wireNavigate() }}
class="block px-4 py-2 text-sm truncate hover:bg-neutral-100 dark:hover:bg-coolgray-200 {{ $project->uuid === $currentProjectUuid ? 'dark:text-warning font-semibold' : '' }}"
@ -130,7 +130,7 @@ class="absolute z-20 top-full mt-1 left-0 sm:left-auto max-w-[calc(100vw-1rem)]"
x-init="$nextTick(() => { const rect = $el.getBoundingClientRect(); if (rect.right > window.innerWidth) { $el.style.left = 'auto'; $el.style.right = '0'; } })">
<!-- Environment List -->
<div
class="relative w-48 bg-white dark:bg-coolgray-100 rounded-md shadow-lg py-1 border border-neutral-200 dark:border-coolgray-200 max-h-96 overflow-y-auto scrollbar">
class="relative w-48 bg-white dark:bg-coolgray-100 rounded-md shadow-[var(--shadow-dropdown)] py-1 border border-neutral-200 dark:border-coolgray-200 max-h-96 overflow-y-auto scrollbar">
@foreach ($environments as $environment)
@php
$envDatabases = collect()
@ -205,7 +205,7 @@ class="flex items-center gap-2 px-4 py-2 text-sm hover:bg-neutral-100 dark:hover
:style="'position: absolute; left: 100%; top: ' + (envPositions['{{ $environment->uuid }}'] || 0) + 'px; z-index: 30;'"
class="flex flex-col sm:flex-row items-start pl-1">
<div
class="relative w-56 bg-white dark:bg-coolgray-100 rounded-md shadow-lg py-1 border border-neutral-200 dark:border-coolgray-200 max-h-96 overflow-y-auto scrollbar">
class="relative w-56 bg-white dark:bg-coolgray-100 rounded-md shadow-[var(--shadow-dropdown)] py-1 border border-neutral-200 dark:border-coolgray-200 max-h-96 overflow-y-auto scrollbar">
@foreach ($envResources as $envResource)
@php
$resType = $envResource['type'];

View file

@ -28,7 +28,7 @@ class="button button-highlighted">
<div class="grid grid-cols-1 gap-3 p-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($tokens as $token)
<a wire:key="{{ $provider }}-token-{{ $token->id }}"
class="group flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('server.create.token', ['type' => $routeType ?: $provider, 'token_uuid' => $token->uuid]) }}"
{{ wireNavigate() }}>
<div class="flex items-start gap-3">

View file

@ -14,7 +14,7 @@ class="terminal-theme-trigger flex h-8 items-center gap-2 rounded-md px-2.5 text
</button>
<div x-cloak x-show="themeOpen" x-transition.origin.top.right
class="console-theme-selector absolute top-11 right-0 z-50 max-h-80 w-56 overflow-y-auto rounded-lg border border-neutral-200 bg-white p-1 shadow-[0_18px_50px_rgba(0,0,0,0.18)] dark:border-white/[0.1] dark:bg-[#111113] dark:shadow-[0_18px_50px_rgba(0,0,0,0.55)]">
class="console-theme-selector absolute top-11 right-0 z-50 max-h-80 w-56 overflow-y-auto rounded-lg border border-neutral-200 bg-white p-1 shadow-[var(--shadow-dropdown)] dark:border-white/[0.1] dark:bg-[#111113]">
@foreach ($themes as $theme)
<button type="button"
class="flex h-8 w-full items-center gap-2 rounded-md px-2 text-left text-[11px] text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-neutral-950 dark:text-white/65 dark:hover:bg-white/[0.07] dark:hover:text-white"

View file

@ -20,7 +20,7 @@
<div class="w-full">
<div
class="grid grid-cols-4 overflow-hidden rounded-[10px] border border-neutral-200 bg-white dark:border-white/[0.08] dark:bg-white/[0.025]">
class="grid grid-cols-4 overflow-hidden rounded-[10px] border border-neutral-200 bg-white dark:border-white/[0.08] dark:bg-white/[0.05]">
@foreach ($steps as $stepNumber => $label)
<div
class="flex min-h-10 items-center justify-center gap-2 border-r border-neutral-200 px-2 text-[11px] font-medium last:border-r-0 dark:border-white/[0.08] sm:px-3"

View file

@ -69,29 +69,42 @@ class="flex h-full items-center gap-0.5 min-w-0 flex-1 border-b border-neutral-2
</div>
</header>
{{-- ============ MOBILE SLIDE-OVER SIDEBAR ============ --}}
<div class="relative z-[1000] lg:hidden" :class="open ? 'block' : 'hidden'" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-black/80" x-on:click="open = false"></div>
<div class="fixed inset-y-0 right-0 flex h-full">
<div
class="relative flex h-full w-full max-w-56 min-w-0 flex-col border-l border-neutral-200 bg-white shadow-xl dark:border-white/[0.12] dark:bg-panel">
<div class="absolute top-0 right-full flex w-16 justify-center pt-5">
<button type="button" class="-m-2.5 p-2.5" x-on:click="open = !open">
<span class="sr-only">Close sidebar</span>
<svg class="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
{{-- ============ MOBILE SLIDE-OVER SIDEBAR (shadcn-style sheet) ============ --}}
<div class="mobile-sidebar-sheet relative z-[1000] lg:hidden" role="dialog" aria-modal="true"
x-on:keydown.escape.window="open = false"
x-on:livewire:navigated.window="open = false"
x-effect="document.body.classList.toggle('overflow-hidden', open)">
{{-- Scrim: fades in/out --}}
<div class="fixed inset-0 bg-black/50" x-show="open" x-cloak x-on:click="open = false"
x-transition:enter="transition-opacity ease-out duration-300"
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-in duration-200"
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"></div>
{{-- Panel: slides in from the right (iOS drawer curve), exits faster --}}
<div class="fixed inset-y-0 right-0 flex" :class="!open && 'pointer-events-none'">
<div x-show="open" x-cloak
x-transition:enter="transform transition ease-[cubic-bezier(0.32,0.72,0,1)] duration-300"
x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0"
x-transition:leave="transform transition ease-in duration-200"
x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full"
class="relative flex h-full w-72 max-w-[85vw] min-w-0 flex-col border-l border-neutral-200 bg-white shadow-2xl dark:border-white/[0.12] dark:bg-panel">
<div data-mobile-sidebar-brand
class="flex h-12 shrink-0 items-center justify-between gap-1.5 border-b border-neutral-200 px-4 dark:border-white/[0.06]">
<div class="flex min-w-0 items-baseline gap-1.5">
<a href="/" {{ wireNavigate() }} title="Coolify"
class="text-[15px] font-semibold tracking-tight text-black transition-opacity hover:opacity-80 dark:text-white">
Coolify
</a>
<x-version class="!text-[10.5px] font-medium text-neutral-400 dark:text-fg-faint !opacity-100 hover:!opacity-100 hover:text-black dark:hover:text-fg" />
</div>
<button type="button" x-on:click="open = false" aria-label="Close menu"
class="-mr-1.5 flex size-8 shrink-0 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-neutral-100 hover:text-black active:scale-95 dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg">
<svg class="size-5" fill="none" viewBox="0 0 24 24" stroke-width="1.75"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div data-mobile-sidebar-brand
class="flex h-12 shrink-0 items-center gap-1.5 border-b border-neutral-200 px-4 dark:border-white/[0.06]">
<a href="/" {{ wireNavigate() }} title="Coolify"
class="text-[15px] font-semibold tracking-tight text-black transition-opacity hover:opacity-80 dark:text-white">
Coolify
</a>
<x-version class="!text-[10.5px] font-medium text-neutral-400 dark:text-fg-faint !opacity-100 hover:!opacity-100 hover:text-black dark:hover:text-fg" />
</div>
<div class="flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto pb-2 scrollbar">
<x-navbar />
</div>
@ -128,7 +141,8 @@ class="hidden shrink-0 items-center"></div>
<livewire:upgrade key="mobile-upgrade" />
@endif
<x-top-user-menu />
<button type="button" class="-m-1 p-2 text-neutral-500 dark:text-fg-dim" x-on:click="open = !open">
<button type="button" x-on:click="open = !open"
class="-mr-1 flex size-9 items-center justify-center rounded-md text-neutral-500 transition-transform duration-100 ease-out hover:bg-neutral-100 hover:text-black active:scale-90 dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg">
<span class="sr-only">Open sidebar</span>
<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
@ -140,7 +154,7 @@ class="hidden shrink-0 items-center"></div>
{{-- ============ MAIN ============ --}}
<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="min-h-screen bg-neutral-50 dark:bg-app 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="w-full" :class="pageWidth === 'centered' ? 'mx-auto max-w-[1400px]' : 'max-w-none'">
{{ $slot }}

View file

@ -4,7 +4,7 @@
styles (e.g. [wire\:loading] { display: none }) must be rendered manually too. --}}
@livewireStyles
@livewireScripts
<main class="h-full bg-gray-50 dark:bg-base">
<main class="h-full bg-neutral-50 dark:bg-base">
{{ $slot }}
</main>
@parent

View file

@ -40,7 +40,7 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
Continue
</x-forms.button>
<div
class="inline-flex flex-wrap items-center justify-center gap-0.5 rounded-lg border border-neutral-200 bg-neutral-50 p-0.5 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="inline-flex flex-wrap items-center justify-center gap-0.5 rounded-lg border border-neutral-200 bg-neutral-50 p-0.5 dark:border-white/[0.08] dark:bg-white/[0.05]">
<button type="button" wire:click="skipBoarding"
class="inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[12px] font-medium text-neutral-500 transition-colors hover:bg-white hover:text-coollabs dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-warning">
<x-reicon name="arrow-right" class="size-3.5 shrink-0" />
@ -101,7 +101,7 @@ class="inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[12px] font-
<p class="mb-3 text-sm text-neutral-500 dark:text-neutral-400">Use this machine or connect a server you already manage.</p>
<div class="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
<button
class="group relative cursor-pointer min-h-36 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group relative cursor-pointer min-h-36 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">
<span role="button" tabindex="0" aria-label="About this machine"
data-tooltip="The machine running Coolify. Not recommended for production workloads due to resource contention."
@ -125,7 +125,7 @@ class="absolute top-3 right-3 flex size-6 items-center justify-center rounded-fu
<button
class="group relative cursor-pointer min-h-36 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group relative cursor-pointer min-h-36 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
wire:target="setServerType('remote')" wire:click="setServerType('remote')">
<span role="button" tabindex="0" aria-label="About remote servers"
data-tooltip="Any SSH-accessible server, including cloud VPS, bare metal, and self-hosted infrastructure."
@ -157,7 +157,7 @@ class="absolute top-3 right-3 flex size-6 items-center justify-center rounded-fu
<x-modal-input title="Connect a Hetzner Server" isFullWidth>
<x-slot:content>
<div
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex h-full flex-col gap-4 text-left">
<img src="{{ asset('svgs/hetzner.svg') }}" alt="Hetzner"
class="size-10 shrink-0">
@ -175,7 +175,7 @@ class="size-10 shrink-0">
<x-modal-input title="Connect a Vultr Server" isFullWidth>
<x-slot:content>
<div
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex h-full flex-col gap-4 text-left">
<img src="https://www.vultr.com/media/logo_ondark.svg" alt="Vultr"
class="h-10 w-28 shrink-0 object-contain object-left">
@ -193,7 +193,7 @@ class="h-10 w-28 shrink-0 object-contain object-left">
<x-modal-input title="Connect a DigitalOcean Server" isFullWidth>
<x-slot:content>
<div
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative cursor-pointer flex h-full min-h-36 flex-col rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex h-full flex-col gap-4 text-left">
<x-digital-ocean-icon class="size-10 shrink-0" />
<div class="min-h-0 flex-1">
@ -279,7 +279,7 @@ class="bg-red-200 dark:bg-red-900 px-1 rounded-sm">~/.ssh/authorized_keys</code>
@endphp
<div class="w-full space-y-4">
<div
class="rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.05]">
<form wire:submit="selectExistingPrivateKey"
class="flex flex-col gap-3 sm:flex-row sm:items-end">
<div class="min-w-0 flex-1">
@ -304,7 +304,7 @@ class="bg-[var(--coollabs-base)] px-2.5 text-[10px] font-semibold uppercase trac
@endif
<div class="grid w-full grid-cols-1 gap-3 lg:grid-cols-2">
<button type="button"
class="group flex h-full min-h-28 items-start gap-3 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex h-full min-h-28 items-start gap-3 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
wire:target="setPrivateKey('own')" wire:click="setPrivateKey('own')">
<span
class="flex size-9 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.035] dark:text-fg-dim">
@ -318,7 +318,7 @@ class="flex size-9 shrink-0 items-center justify-center rounded-lg border border
</span>
</button>
<button type="button"
class="group flex h-full min-h-28 items-start gap-3 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex h-full min-h-28 items-start gap-3 rounded-[10px] border border-neutral-200 bg-white p-4 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
wire:target="setPrivateKey('create')" wire:click="setPrivateKey('create')">
<span
class="flex size-9 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.035] dark:text-fg-dim">
@ -597,7 +597,7 @@ class="text-[10px] font-semibold uppercase tracking-[0.08em] text-neutral-400 da
Deploy your first resource
</x-forms.button>
<div
class="inline-flex flex-wrap items-center justify-center gap-0.5 rounded-lg border border-neutral-200 bg-neutral-50 p-0.5 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="inline-flex flex-wrap items-center justify-center gap-0.5 rounded-lg border border-neutral-200 bg-neutral-50 p-0.5 dark:border-white/[0.08] dark:bg-white/[0.05]">
<button type="button" wire:click="skipBoarding"
class="inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[12px] font-medium text-neutral-500 transition-colors hover:bg-white hover:text-coollabs dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-warning">
<x-reicon name="arrow-right" class="size-3.5 shrink-0" />
@ -622,7 +622,7 @@ class="inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[12px] font-
@if ($currentState !== 'welcome' && $currentState !== 'create-resource')
<div class="mx-auto mt-6 flex w-full max-w-3xl flex-col items-center gap-3">
<div
class="inline-flex flex-wrap items-center justify-center gap-0.5 rounded-lg border border-neutral-200 bg-neutral-50 p-0.5 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="inline-flex flex-wrap items-center justify-center gap-0.5 rounded-lg border border-neutral-200 bg-neutral-50 p-0.5 dark:border-white/[0.08] dark:bg-white/[0.05]">
<button type="button" wire:click="skipBoarding"
class="inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[12px] font-medium text-neutral-500 transition-colors hover:bg-white hover:text-coollabs dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-warning">
<x-reicon name="arrow-right" class="size-3.5 shrink-0" />

View file

@ -57,7 +57,7 @@ class="inline-flex shrink-0 items-center gap-1 text-[12px] font-medium text-neut
@endphp
<article
class="group relative flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<a href="{{ $project->navigateTo() }}" {{ wireNavigate() }}
class="absolute inset-0 rounded-xl"
aria-label="Open {{ $project->name }}"></a>
@ -190,7 +190,7 @@ class="button button-highlighted">
<a href="{{ route('server.show', ['server_uuid' => $server->uuid]) }}"
{{ wireNavigate() }} aria-label="Open {{ $server->name }}"
class="group relative flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 min-w-0 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
@if ($server->isMetricsEnabled())
<livewire:dashboard.server-metrics-chart :server="$server"
:key="'dashboard-server-metrics-'.$server->uuid" />

View file

@ -41,7 +41,7 @@
<div class="flex min-w-0 flex-col gap-4">
@if ($hasActiveDeployments)
<div
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="border-b border-neutral-200 px-4 py-2.5 dark:border-white/[0.08]">
<h3 class="text-[12px]! leading-4! font-semibold! text-black dark:text-fg">
Active
@ -52,7 +52,7 @@ class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm d
</div>
<div
class="dashboard-deployment-table-grid hidden items-center gap-4 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 md:grid dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
class="dashboard-deployment-table-grid hidden items-center gap-4 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 md:grid dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<span>Application</span>
<span>Environment</span>
<span>Server</span>
@ -110,7 +110,7 @@ class="dashboard-deployment-table-grid group block border-b border-neutral-200 p
@if ($hasRecentDeployments)
<div
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="border-b border-neutral-200 px-4 py-2.5 dark:border-white/[0.08]">
<h3 class="text-[12px]! leading-4! font-semibold! text-black dark:text-fg">
Recent
@ -121,7 +121,7 @@ class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm d
</div>
<div
class="dashboard-deployment-table-grid hidden items-center gap-4 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 md:grid dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
class="dashboard-deployment-table-grid hidden items-center gap-4 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[11px] font-medium text-neutral-500 md:grid dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<span>Application</span>
<span>Environment</span>
<span>Server</span>

View file

@ -62,7 +62,7 @@ class="button button-highlighted">
<div x-cloak x-show="viewMode === 'grid'" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($destinations as $destination)
<a x-show="matches(@js([$destination->name, $destination->server->name, $destination->getMorphClass() === 'App\\Models\\SwarmDocker' ? 'Docker Swarm' : 'Standalone Docker']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a x-show="matches(@js([$destination->name, $destination->server->name, $destination->getMorphClass() === 'App\\Models\\SwarmDocker' ? 'Docker Swarm' : 'Standalone Docker']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}
href="{{ route('destination.show', ['destination_uuid' => data_get($destination, 'uuid')]) }}">
<div class="flex items-start gap-3">
@ -90,8 +90,8 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
</a>
@endforeach
</div>
<div x-show="viewMode === 'table'" class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.7fr)_10rem] 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.025] dark:text-fg-faint">
<div x-show="viewMode === 'table'" class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.7fr)_10rem] 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>Destination</div><div>Server</div><div>Type</div>
</div>
@foreach ($destinations as $destination)

View file

@ -31,7 +31,7 @@ class="h-8! w-full rounded-lg! border-neutral-200! bg-white! py-0! pr-3! pl-8! t
<div class="overflow-x-auto">
<div
class="grid min-w-[680px] grid-cols-[minmax(10rem,.8fr)_minmax(10rem,.8fr)_minmax(12rem,1fr)_8rem] 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.025] dark:text-fg-faint">
class="grid min-w-[680px] grid-cols-[minmax(10rem,.8fr)_minmax(10rem,.8fr)_minmax(12rem,1fr)_8rem] 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>Project</div>
<div>Environment</div>
<div>Resource</div>

View file

@ -751,7 +751,7 @@ class="relative flex min-h-full items-start justify-center p-4 sm:items-center">
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="{{ $createModalShell }}"
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-dropdown)">
<header class="flex-nowrap!">
<h3 class="min-w-0 flex-1 truncate">New project</h3>
<button type="button" @click="modalOpen=false" class="{{ $createModalClose }}">
@ -794,7 +794,7 @@ class="relative flex min-h-full items-start justify-center p-4 sm:items-center">
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="{{ $createModalShell }}"
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-dropdown)">
<header class="flex-nowrap!">
<h3 class="min-w-0 flex-1 truncate">New team</h3>
<button type="button" @click="modalOpen=false" class="{{ $createModalClose }}">
@ -837,7 +837,7 @@ class="relative flex min-h-full items-start justify-center p-4 sm:items-center">
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="{{ $createModalShell }}"
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-dropdown)">
<header class="flex-nowrap!">
<h3 class="min-w-0 flex-1 truncate">New S3 storage</h3>
<button type="button" @click="modalOpen=false" class="{{ $createModalClose }}">
@ -880,7 +880,7 @@ class="relative flex min-h-full items-start justify-center p-4 sm:items-center">
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="{{ $createModalShell }}"
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-dropdown)">
<header class="flex-nowrap!">
<h3 class="min-w-0 flex-1 truncate">New private key</h3>
<button type="button" @click="modalOpen=false" class="{{ $createModalClose }}">
@ -923,7 +923,7 @@ class="relative flex min-h-full items-start justify-center p-4 sm:items-center">
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="{{ $createModalShell }}"
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-dropdown)">
<header class="flex-nowrap!">
<h3 class="min-w-0 flex-1 truncate">New GitHub app</h3>
<button type="button" @click="modalOpen=false" class="{{ $createModalClose }}">

View file

@ -72,7 +72,7 @@
@click="setTheme('{{ $option['value'] }}')"
@keydown.enter.prevent="setTheme('{{ $option['value'] }}')"
@endif
class="group relative 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="group relative 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.05] dark:hover:border-white/[0.12]"
:class="theme === '{{ $option['value'] }}'
? 'ring-1 ring-coollabs/30 border-coollabs/40 dark:ring-warning/30 dark:border-warning/40'
: ''">
@ -126,7 +126,7 @@ class="absolute inset-0 z-10 h-full w-full cursor-pointer opacity-0" />
['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="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.05] 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'
: ''">

View file

@ -275,7 +275,7 @@ class="flex items-end gap-2">
@if (session('status') === 'two-factor-authentication-confirmed'
|| session('status') === 'recovery-codes-generated')
<div
class="grid gap-2 rounded-lg border border-neutral-200 bg-neutral-50 p-4 font-mono text-xs text-neutral-700 sm:grid-cols-2 dark:border-white/[0.07] dark:bg-white/[0.025] dark:text-fg-dim">
class="grid gap-2 rounded-lg border border-neutral-200 bg-neutral-50 p-4 font-mono text-xs text-neutral-700 sm:grid-cols-2 dark:border-white/[0.07] dark:bg-white/[0.05] dark:text-fg-dim">
@foreach (request()->user()->recoveryCodes() as $code)
<div>{{ $code }}</div>
@endforeach

View file

@ -5,7 +5,7 @@
</div>
<p
class="rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2.5 text-[12px] text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-dim">
class="rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2.5 text-[12px] text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">
A production environment will be created automatically.
</p>

View file

@ -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-none lg:mt-0">
<div class="grid min-w-0 gap-8 xl:grid-cols-[210px_minmax(0,1fr)] xl:gap-8">
<section class="application-settings-workspace w-full max-w-none">
<div class="grid min-w-0 gap-4 xl:grid-cols-[236px_minmax(0,1fr)] xl:gap-8">
<x-application.configuration-sidebar :application="$application" :current-route="$currentRoute" />
<div class="min-w-0">

View file

@ -48,7 +48,7 @@
$domainCount = countDomains($fqdn);
}
@endphp
<div class="flex items-center gap-3 rounded-lg border border-neutral-200 bg-neutral-50/60 px-4 py-3 dark:border-white/[0.07] dark:bg-white/[0.025]">
<div class="flex items-center gap-3 rounded-lg border border-neutral-200 bg-neutral-50/60 px-4 py-3 dark:border-white/[0.07] dark:bg-white/[0.05]">
<div class="flex min-w-0 flex-1 items-center gap-3">
<div class="flex size-9 shrink-0 items-center justify-center rounded-md bg-neutral-200/70 text-neutral-600 dark:bg-white/[0.07] dark:text-fg-dim">
<x-reicon name="globe" class="size-4" />

View file

@ -26,11 +26,12 @@
@endphp
<div>
<div class="mb-3 w-full xl:hidden">
<div class="flex min-w-0 flex-col items-start gap-2">
<h1 class="min-w-0 max-w-full truncate text-[24px]! leading-7! font-semibold! tracking-tight! text-black dark:text-fg">
{{-- Identity row: name truncates, status + links stay pinned right. --}}
<div class="flex w-full min-w-0 items-center gap-3">
<h1 class="min-w-0 flex-1 truncate text-[22px]! leading-7! font-semibold! tracking-tight! text-black dark:text-fg">
{{ $application->name }}
</h1>
<div class="relative flex w-full min-w-0 items-center gap-2">
<div class="flex shrink-0 items-center gap-2">
<x-status-summary :status="$application->status" />
<x-applications.links :application="$application" compact />
</div>

View file

@ -25,7 +25,7 @@
@if (blank($privateKeyId))
<div
class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-3 py-2.5 ring-1 ring-neutral-200 dark:bg-white/[0.025] dark:ring-white/[0.07]">
class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-3 py-2.5 ring-1 ring-neutral-200 dark:bg-white/[0.05] dark:ring-white/[0.07]">
<span class="text-[12px] text-neutral-500 dark:text-fg-dim">Connected source</span>
<span class="text-[12px] font-medium text-neutral-900 dark:text-fg">
{{ data_get($application, 'source.name', 'No source connected') }}
@ -48,7 +48,7 @@ class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-
<x-application.settings-section title="Deploy key"
description="The SSH key Coolify uses to clone this private repository.">
<div
class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-3 py-2.5 ring-1 ring-neutral-200 dark:bg-white/[0.025] dark:ring-white/[0.07]">
class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-3 py-2.5 ring-1 ring-neutral-200 dark:bg-white/[0.05] dark:ring-white/[0.07]">
<span class="text-[12px] text-neutral-500 dark:text-fg-dim">Attached private key</span>
<span class="text-[12px] font-medium text-neutral-900 dark:text-fg">{{ $privateKeyName }}</span>
</div>
@ -56,7 +56,7 @@ class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-
<div class="grid gap-2 sm:grid-cols-2">
@forelse ($privateKeys as $key)
<button type="button" wire:click="setPrivateKey('{{ $key->id }}')"
class="flex min-h-11 items-center rounded-lg border border-neutral-200 bg-white px-3 text-left text-[12px] font-medium transition-colors hover:bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:bg-white/[0.05]">
class="flex min-h-11 items-center rounded-lg border border-neutral-200 bg-white px-3 text-left text-[12px] font-medium transition-colors hover:bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:bg-white/[0.05]">
{{ $key->name }}
</button>
@empty
@ -129,7 +129,7 @@ class="size-4 shrink-0 text-coollabs dark:text-warning" />
shortConfirmationLabel="Confirmation text" :confirmWithPassword="false">
<x-slot:trigger>
<button type="button"
class="group flex w-full min-h-16 items-center gap-3 rounded-xl border border-neutral-200 bg-white p-3 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:bg-neutral-50 hover:shadow-md focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14] dark:hover:bg-white/[0.05]">
class="group flex w-full min-h-16 items-center gap-3 rounded-xl border border-neutral-200 bg-white p-3 text-left shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:bg-neutral-50 hover:shadow-md focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14] dark:hover:bg-white/[0.05]">
<div
class="flex size-9 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 transition-colors group-hover:border-neutral-300 group-hover:text-neutral-700 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim dark:group-hover:border-white/[0.12] dark:group-hover:text-fg">
<x-git-icon class="size-4" :git="$sourceMorph" />

View file

@ -105,7 +105,7 @@
class="flex min-h-20 items-center gap-3 rounded-[10px] border p-3 text-left transition-colors"
:class="restoreType === 'file'
? 'border-coollabs/35 bg-coollabs/[0.06] text-coollabs dark:border-warning/30 dark:bg-warning/[0.08] dark:text-warning'
: 'border-neutral-200 bg-white hover:border-neutral-300 dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]'">
: 'border-neutral-200 bg-white hover:border-neutral-300 dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]'">
<span
class="flex size-9 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-white/[0.06]">
<x-reicon name="file" class="size-4" />
@ -122,7 +122,7 @@ class="flex size-9 shrink-0 items-center justify-center rounded-lg bg-neutral-10
class="flex min-h-20 items-center gap-3 rounded-[10px] border p-3 text-left transition-colors"
:class="restoreType === 's3'
? 'border-coollabs/35 bg-coollabs/[0.06] text-coollabs dark:border-warning/30 dark:bg-warning/[0.08] dark:text-warning'
: 'border-neutral-200 bg-white hover:border-neutral-300 dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]'">
: 'border-neutral-200 bg-white hover:border-neutral-300 dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]'">
<span
class="flex size-9 shrink-0 items-center justify-center rounded-lg bg-neutral-100 dark:bg-white/[0.06]">
<x-reicon name="storages" class="size-4" />
@ -139,7 +139,7 @@ class="flex size-9 shrink-0 items-center justify-center rounded-lg bg-neutral-10
{{-- File Restore Section --}}
@can('update', $this->resource)
<div x-cloak x-show="restoreType === 'file'"
class="mt-4 rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="mt-4 rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.05]">
<form class="flex flex-col gap-3 sm:flex-row sm:items-end">
<div class="min-w-0 flex-1">
<x-forms.input label="File path on the server"
@ -158,7 +158,7 @@ class="mt-4 rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:bord
</div>
<form action="{{ route('upload.backup', ['databaseUuid' => $resourceUuid]) }}"
class="dropzone rounded-lg! border! border-dashed! border-neutral-300! bg-white! dark:border-white/[0.12]! dark:bg-white/[0.025]!"
class="dropzone rounded-lg! border! border-dashed! border-neutral-300! bg-white! dark:border-white/[0.12]! dark:bg-white/[0.05]!"
id="my-dropzone" wire:ignore>
@csrf
</form>
@ -206,7 +206,7 @@ class="mt-4 flex flex-col gap-3 rounded-lg border border-neutral-200 bg-white p-
->all();
@endphp
<div x-cloak x-show="restoreType === 's3'"
class="mt-4 rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="mt-4 rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="grid gap-4 sm:grid-cols-2">
<x-forms.listbox id="s3StorageId" label="S3 storage" :options="$s3StorageOptions"
placeholder="Select storage" live />

View file

@ -56,7 +56,7 @@ class="input h-8! w-full pl-8! text-[13px]!" placeholder="Search backups" />
description="Create a schedule to start protecting this database."
icon-name="storages" />
@else
<div x-cloak x-show="search === '' || hasMatches()" class="data-table overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div x-cloak x-show="search === '' || hasMatches()" class="data-table overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="data-table-header scheduled-backups-table-grid">
<span>Schedule</span>
<span>Latest run</span>

View file

@ -103,7 +103,7 @@ class="flex size-7.5 items-center justify-center rounded-md transition-colors"
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
<template x-for="project in paginatedProjects" :key="project.uuid">
<article
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<a :href="project.href" {{ wireNavigate() }} class="absolute inset-0 rounded-xl"
:aria-label="`Open ${project.name}`"></a>
<div class="flex items-start gap-3">
@ -151,15 +151,15 @@ class="flex size-7.5 items-center justify-center rounded-md text-neutral-400 tra
</article>
</template>
</div>
<x-client-pagination x-show="filteredProjects.length > 0" class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]"
<x-client-pagination x-show="filteredProjects.length > 0" class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]"
summary="`${rangeStart}-${rangeEnd} of ${filteredProjects.length}`" page-size-model="pageSize"
storage-key="coolify.page-size.projects" :options="[12, 24, 48, 96]" />
</div>
<div x-show="viewMode === 'table'"
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div
class="projects-table-grid 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.025] dark:text-fg-faint">
class="projects-table-grid 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>Project</div>
<div>Environments</div>
<div>Resources</div>
@ -212,7 +212,7 @@ class="flex size-7 items-center justify-center rounded-md text-neutral-400 trans
</div>
<div x-show="filteredProjects.length === 0"
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.025]">
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-reicon name="search" class="mb-3 size-6 text-neutral-300 dark:text-fg-faint" />
<p class="text-[13px] font-medium">No matching projects</p>
<p class="mt-1 text-[12px] text-neutral-500 dark:text-fg-dim">

View file

@ -111,7 +111,7 @@ class="application-settings-section-body grid grid-cols-1 justify-start gap-3 te
<article role="button" tabindex="0" :aria-label="'Deploy ' + application.name"
@click="setType(application.id)" @keydown.enter.self.prevent="setType(application.id)"
@keydown.space.self.prevent="setType(application.id)"
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex min-w-0 items-start gap-3">
<div
class="flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.04]">
@ -157,7 +157,7 @@ class="mt-auto flex items-center gap-1.5 border-t border-neutral-200 pt-3 dark:b
<article role="button" tabindex="0" :aria-label="'Deploy ' + application.name"
@click="setType(application.id)" @keydown.enter.self.prevent="setType(application.id)"
@keydown.space.self.prevent="setType(application.id)"
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex min-w-0 items-start gap-3">
<div
class="flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.04]">
@ -206,7 +206,7 @@ class="application-settings-section-body grid grid-cols-1 justify-start gap-3 te
<article role="button" tabindex="0" :aria-label="'Deploy ' + database.name"
@click="setType(database.id)" @keydown.enter.self.prevent="setType(database.id)"
@keydown.space.self.prevent="setType(database.id)"
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex min-w-0 items-center gap-3">
<div
class="flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.04]">
@ -283,7 +283,7 @@ class="text-[11px] text-neutral-500 dark:text-fg-faint">
@click="setType('one-click-service-' + service.id)"
@keydown.enter.self.prevent="setType('one-click-service-' + service.id)"
@keydown.space.self.prevent="setType('one-click-service-' + service.id)"
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-48 cursor-pointer flex-col rounded-xl border border-neutral-200 bg-white p-4 transition-colors hover:border-neutral-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-accent dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex min-w-0 items-start gap-3">
<div
class="flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.04]">

View file

@ -166,9 +166,9 @@ class="flex size-7.5 items-center justify-center rounded-md transition-colors"
</div>
<div x-show="viewMode === 'table'"
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div
class="environment-resource-grid 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.025] dark:text-fg-faint">
class="environment-resource-grid 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 class="resource-type">Type</div>
<div>Status</div>
@ -271,7 +271,7 @@ class="flex min-h-52 flex-col items-center justify-center px-6 text-center">
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
<template x-for="item in paginatedResources" :key="item.uuid">
<article
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<a :href="item.hrefLink"
@click="if (item.version === 'v5') { $event.preventDefault(); window.location.assign(item.hrefLink) }"
{{ wireNavigate() }} class="absolute inset-0 rounded-xl"
@ -320,7 +320,7 @@ class="relative z-10 max-w-full self-start truncate text-[11px] text-neutral-500
</div>
<div x-show="filteredResources.length === 0"
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.025]">
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-reicon name="search" class="mb-3 size-6 text-neutral-300 dark:text-fg-faint" />
<p class="text-[13px] font-medium">No matching resources</p>
<p class="mt-1 text-[12px] text-neutral-500 dark:text-fg-dim">
@ -328,7 +328,7 @@ class="flex min-h-52 flex-col items-center justify-center rounded-xl border bord
</p>
</div>
<x-client-pagination x-show="filteredResources.length > 0"
class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]"
class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]"
summary="filteredResources.length === 0 ? '0 resources' : `${rangeStart}-${rangeEnd} of ${filteredResources.length}`"
page-size-model="pageSize" storage-key="coolify.page-size.environment-resources" />
</div>

View file

@ -144,10 +144,10 @@ class="flex size-7.5 items-center justify-center rounded-md transition-colors"
<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.025]'">
: '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.025] dark:text-fg-faint">
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>

View file

@ -25,7 +25,7 @@ class="flex min-h-0 flex-col gap-3">
</div>
<div
class="flex flex-col items-stretch gap-2 rounded-lg border border-neutral-200 bg-neutral-50 p-1 sm:flex-row sm:flex-wrap sm:items-center dark:border-white/[0.08] dark:bg-white/[0.025]">
class="flex flex-col items-stretch gap-2 rounded-lg border border-neutral-200 bg-neutral-50 p-1 sm:flex-row sm:flex-wrap sm:items-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-forms.checkbox label="Escape special characters in labels"
helper="By default, $ (and other characters) is escaped. A $ in a label is saved as $$. Turn this off to use environment variables inside labels."
id="isContainerLabelEscapeEnabled" instantSave />

View file

@ -150,7 +150,7 @@ class="terminal-session-target-trigger flex h-8 max-w-[34rem] min-w-48 items-cen
</svg>
</button>
<div x-cloak x-show="containerOpen" x-transition.origin.top.left
class="terminal-target-picker terminal-target-list absolute top-11 left-0 z-50 max-h-72 w-80 overflow-y-auto rounded-lg border p-1 shadow-[0_18px_50px_rgba(0,0,0,0.35)]">
class="terminal-target-picker terminal-target-list absolute top-11 left-0 z-50 max-h-72 w-80 overflow-y-auto rounded-lg border p-1 shadow-[var(--shadow-dropdown)]">
<template x-for="option in containerOptions" :key="option.value">
<button type="button"
class="flex h-8 w-full items-center gap-2 rounded-md px-2 text-left text-[11px] text-white/65 transition-colors hover:bg-white/[0.07] hover:text-white"
@ -180,7 +180,7 @@ class="size-3 shrink-0 text-[#fcd452]" viewBox="0 0 12 12"
@if ($type !== 'server' && $containers->count() > 1)
<div x-cloak x-show="!targetChosen" data-terminal-target-picker="launcher"
class="absolute inset-0 z-20 flex items-start justify-start p-6 sm:p-10">
<div class="terminal-target-picker w-full max-w-md rounded-lg border p-2 shadow-[0_18px_50px_rgba(0,0,0,0.28)]">
<div class="terminal-target-picker w-full max-w-md rounded-lg border p-2 shadow-[var(--shadow-dropdown)]">
<div class="px-2 pt-1 pb-2">
<div class="text-sm font-semibold text-white/80">Start a terminal session</div>
<div class="mt-0.5 text-[11px] text-white/45">

View file

@ -25,7 +25,7 @@
@if ($executionCount > 0)
<div class="data-table w-full overflow-x-auto">
<div
class="data-table-header volume-backup-executions-grid border-b border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="data-table-header volume-backup-executions-grid border-b border-neutral-200 bg-neutral-50 dark:border-white/[0.08] dark:bg-white/[0.05]">
<span>Status</span>
<span>Archive</span>
<span>Time</span>
@ -129,7 +129,7 @@ class="icon-button shrink-0 text-red-500 hover:text-red-600 dark:text-red-400 da
@if ($execution->message)
<pre
class="volume-backup-execution-message col-span-6 mt-2 max-h-32 overflow-auto rounded-lg border border-neutral-200 bg-neutral-50 p-2 text-[11px] whitespace-pre-wrap text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-dim">{{ $execution->message }}</pre>
class="volume-backup-execution-message col-span-6 mt-2 max-h-32 overflow-auto rounded-lg border border-neutral-200 bg-neutral-50 p-2 text-[11px] whitespace-pre-wrap text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">{{ $execution->message }}</pre>
@endif
</div>
@endforeach

View file

@ -16,7 +16,7 @@
</div>
</x-slot:actions>
<div class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-3 py-2.5 ring-1 ring-neutral-200 dark:bg-white/[0.025] dark:ring-white/[0.07]">
<div class="mb-4 flex items-center justify-between gap-3 rounded-lg bg-neutral-50 px-3 py-2.5 ring-1 ring-neutral-200 dark:bg-white/[0.05] dark:ring-white/[0.07]">
<span class="text-[12px] text-neutral-500 dark:text-fg-dim">
{{ $backup?->targetType() ?? ($storage instanceof \App\Models\LocalFileVolume ? 'Directory' : 'Volume') }}
</span>

View file

@ -123,7 +123,7 @@ class="flex size-7.5 items-center justify-center rounded-md transition-colors"
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
<template x-for="environment in paginatedEnvironments" :key="environment.uuid">
<article
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<a :href="environment.href" {{ wireNavigate() }} class="absolute inset-0 rounded-xl"
:aria-label="`Open ${environment.name}`"></a>
@ -165,15 +165,15 @@ class="flex size-7.5 items-center justify-center rounded-md text-neutral-400 tra
</article>
</template>
</div>
<x-client-pagination x-show="filteredEnvironments.length > 0" class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]"
<x-client-pagination x-show="filteredEnvironments.length > 0" class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]"
summary="`${rangeStart}-${rangeEnd} of ${filteredEnvironments.length}`" page-size-model="pageSize"
storage-key="coolify.page-size.project-environments" :options="[12, 24, 48, 96]" />
</div>
<div x-show="viewMode === 'table'"
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div
class="environments-table-grid 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.025] dark:text-fg-faint">
class="environments-table-grid 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>Environment</div>
<div class="environment-resource-count">Resources</div>
<div class="environment-description">Description</div>
@ -222,7 +222,7 @@ class="flex size-7 items-center justify-center rounded-md text-neutral-400 trans
</div>
<div x-show="filteredEnvironments.length === 0"
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.025]">
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-reicon name="search" class="mb-3 size-6 text-neutral-300 dark:text-fg-faint" />
<p class="text-[13px] font-medium">No matching environments</p>
<p class="mt-1 text-[12px] text-neutral-500 dark:text-fg-dim">

View file

@ -28,7 +28,7 @@ class="button button-highlighted">
icon-name="file-content" size="sm" />
@else
<div>
<div class="grid grid-cols-[minmax(0,1fr)_12rem_1.75rem] items-center gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[13px] font-medium text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
<div class="grid grid-cols-[minmax(0,1fr)_12rem_1.75rem] items-center gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[13px] font-medium text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<div class="pl-11">Script</div>
<div>Last updated</div>
<div class="w-7"></div>

View file

@ -24,7 +24,7 @@
@endif
<div
class="rounded-lg border border-neutral-200 bg-neutral-50 p-3 text-[11px] leading-5 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-dim">
class="rounded-lg border border-neutral-200 bg-neutral-50 p-3 text-[11px] leading-5 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">
Create the token in the
<a :href="providerConsoleUrl"
target="_blank" class="font-medium text-coollabs hover:underline dark:text-warning">

View file

@ -20,7 +20,7 @@ class="button button-highlighted">
description="Add a provider token to provision new cloud servers." icon-name="keys" size="sm" />
@else
<div>
<div class="grid grid-cols-[minmax(0,1fr)_8rem_1.75rem] items-center gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[13px] font-medium text-neutral-500 sm:grid-cols-[minmax(0,1fr)_8rem_minmax(0,1fr)_1.75rem] dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
<div class="grid grid-cols-[minmax(0,1fr)_8rem_1.75rem] items-center gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[13px] font-medium text-neutral-500 sm:grid-cols-[minmax(0,1fr)_8rem_minmax(0,1fr)_1.75rem] dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<div class="pl-11">Token</div>
<div class="text-center">Provider</div>
<div class="hidden sm:block">Description</div>

View file

@ -68,7 +68,7 @@ class="listbox-option justify-start! gap-2.5!" role="menuitem">
icon-name="keys" />
@else
<div>
<div class="grid grid-cols-[minmax(0,1fr)_7rem_1.75rem] items-center gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[13px] font-medium text-neutral-500 sm:grid-cols-[minmax(0,1.2fr)_minmax(0,1fr)_7rem_1.75rem] dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
<div class="grid grid-cols-[minmax(0,1fr)_7rem_1.75rem] items-center gap-3 border-b border-neutral-200 bg-neutral-50 px-4 py-2.5 text-[13px] font-medium text-neutral-500 sm:grid-cols-[minmax(0,1.2fr)_minmax(0,1fr)_7rem_1.75rem] dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<div class="pl-11">Private key</div>
<div class="hidden sm:block">Description</div>
<div class="text-center">Status</div>
@ -115,7 +115,7 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
title="You do not have permission to view this private key">
<div class="flex items-start gap-3">
<div
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-white text-neutral-400 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-faint">
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-white text-neutral-400 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-faint">
<x-reicon name="keys" class="size-4" />
</div>
<div class="min-w-0 flex-1">

View file

@ -24,7 +24,7 @@
<div class="application-settings-section-body is-flush">
<div class="grid grid-cols-1 gap-3 p-3 sm:grid-cols-2 lg:grid-cols-4">
<a href="{{ route('server.create.type', ['type' => 'manual']) }}"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}>
<div class="flex items-start">
<span
@ -52,7 +52,7 @@ class="flex size-8 items-center justify-center rounded-lg border border-neutral-
<div class="application-settings-section-body is-flush">
<div class="grid grid-cols-1 gap-3 p-3 sm:grid-cols-2 lg:grid-cols-3">
<a href="{{ route('server.create.type', ['type' => 'hetzner']) }}"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}>
<div class="flex items-start">
<img src="{{ asset('svgs/hetzner.svg') }}" alt="Hetzner" class="size-8">
@ -66,7 +66,7 @@ class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-whit
</a>
<a href="{{ route('server.create.type', ['type' => 'vultr']) }}"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}>
<div class="flex items-start">
<img src="https://www.vultr.com/media/logo_ondark.svg" alt="Vultr"
@ -81,7 +81,7 @@ class="h-8 w-20 object-contain object-left">
</a>
<a href="{{ route('server.create.type', ['type' => 'digital-ocean']) }}"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}>
<div class="flex items-start">
<x-digital-ocean-icon class="size-8" />

View file

@ -134,7 +134,7 @@ class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
<a x-cloak
x-show="filteredServers.some(server => server.uuid === @js($server->uuid))"
href="{{ $serverRow['href'] }}" {{ wireNavigate() }}
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
@if ($server->isMetricsEnabled())
<livewire:dashboard.server-metrics-chart :server="$server"
:key="'server-index-metrics-'.$server->uuid" />
@ -170,9 +170,9 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
</div>
<div x-show="viewMode === 'table'"
class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div
class="grid min-w-[480px] grid-cols-[minmax(0,1fr)_9.5rem] 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.025] dark:text-fg-faint">
class="grid min-w-[480px] grid-cols-[minmax(0,1fr)_9.5rem] 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>Server</div>
<div>Status</div>
</div>
@ -205,7 +205,7 @@ class="ml-auto flex size-6 shrink-0 items-center justify-center rounded-md"
</div>
<div x-show="filteredServers.length === 0"
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.025]">
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-reicon name="search" class="mb-3 size-6 text-neutral-300 dark:text-fg-faint" />
<p class="text-[13px] font-medium">No matching servers</p>
<p class="mt-1 text-[12px] text-neutral-500 dark:text-fg-dim">Try a different search.</p>

View file

@ -75,7 +75,7 @@
<div class="flex h-full min-h-0 flex-col gap-4 overflow-y-auto scrollbar">
@if ($ask)
<div
class="rounded-[10px] border border-neutral-200 bg-neutral-50 px-4 py-3 text-[13px] leading-5 text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-dim">
class="rounded-[10px] border border-neutral-200 bg-neutral-50 px-4 py-3 text-[13px] leading-5 text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">
This will revalidate the server, install or update Docker Engine, Docker Compose, and related
configuration. Docker Engine will restart, so running containers may be briefly unreachable.
</div>

View file

@ -32,7 +32,7 @@
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($project->environments as $environment)
<a x-show="matches(@js([$environment->name, $environment->description, $project->name]))"
class="group flex min-h-24 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-24 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.environment.show', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid]) }}" {{ wireNavigate() }}>
<div class="flex items-start gap-3">
<div class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim"><x-reicon name="layers" class="size-4" /></div>
@ -46,7 +46,7 @@ class="group flex min-h-24 flex-col rounded-xl border border-neutral-200 bg-whit
@endforeach
</div>
<div x-show="viewMode === 'list'" class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div x-show="viewMode === 'list'" class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
@foreach ($projects as $project)
@foreach ($project->environments as $environment)
<a x-show="matches(@js([$environment->name, $environment->description, $project->name]))"

View file

@ -7,7 +7,7 @@
<div class="w-full">
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.team.index') }}" {{ wireNavigate() }}>
<div
class="flex size-8 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
@ -21,7 +21,7 @@ class="flex size-8 items-center justify-center rounded-lg border border-neutral-
</div>
</a>
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.project.index') }}" {{ wireNavigate() }}>
<div
class="flex size-8 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
@ -35,7 +35,7 @@ class="flex size-8 items-center justify-center rounded-lg border border-neutral-
</div>
</a>
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.environment.index') }}" {{ wireNavigate() }}>
<div
class="flex size-8 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
@ -49,7 +49,7 @@ class="flex size-8 items-center justify-center rounded-lg border border-neutral-
</div>
</a>
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a class="group flex min-h-32 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.server.index') }}" {{ wireNavigate() }}>
<div
class="flex size-8 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">

View file

@ -19,7 +19,7 @@
<div x-cloak x-show="viewMode === 'grid'" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($projects as $project)
<a x-show="matches(@js([$project->name, $project->description]))"
class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.project.show', ['project_uuid' => $project->uuid]) }}" {{ wireNavigate() }}>
<div class="flex items-start gap-3">
<div class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
@ -43,7 +43,7 @@ class="h-full w-full rounded-lg object-cover">
@endforeach
</div>
<div x-show="viewMode === 'list'" class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div x-show="viewMode === 'list'" class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
@foreach ($projects as $project)
<a x-show="matches(@js([$project->name, $project->description]))"
href="{{ route('shared-variables.project.show', ['project_uuid' => $project->uuid]) }}" {{ wireNavigate() }}

View file

@ -18,7 +18,7 @@
<div x-cloak x-show="viewMode === 'grid'" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($servers as $server)
<a x-show="matches(@js([$server->name, $server->description, $server->ip]))"
class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
href="{{ route('shared-variables.server.show', ['server_uuid' => $server->uuid]) }}" {{ wireNavigate() }}>
<div class="flex items-start gap-3">
<div class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim"><x-reicon name="servers" class="size-4" /></div>
@ -29,7 +29,7 @@ class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-whit
@endforeach
</div>
<div x-show="viewMode === 'list'" class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div x-show="viewMode === 'list'" class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
@foreach ($servers as $server)
<a x-show="matches(@js([$server->name, $server->description, $server->ip]))"
href="{{ route('shared-variables.server.show', ['server_uuid' => $server->uuid]) }}" {{ wireNavigate() }}

View file

@ -1,4 +1,4 @@
<div x-show="filteredItems.length === 0" class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.025]">
<div x-show="filteredItems.length === 0" class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-reicon name="search" class="mb-3 size-6 text-neutral-300 dark:text-fg-faint" />
<p class="text-[13px] font-medium">No matching {{ $label }}</p>
<p class="mt-1 text-[12px] text-neutral-500 dark:text-fg-dim">Try a different search.</p>

View file

@ -300,7 +300,7 @@ class="rounded-lg border border-red-300 bg-red-50 p-4 ring-1 ring-inset ring-red
@endif
<div
class="rounded-lg border border-neutral-200 bg-neutral-50 p-3 text-[12px] leading-5 text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.025] dark:text-fg-dim">
class="rounded-lg border border-neutral-200 bg-neutral-50 p-3 text-[12px] leading-5 text-neutral-600 dark:border-white/[0.08] dark:bg-white/[0.05] dark:text-fg-dim">
<p class="font-medium text-black dark:text-fg">Mandatory permissions</p>
<p class="mt-1">Contents: read · Metadata: read · Email: read</p>
</div>

View file

@ -17,7 +17,7 @@ class="h-8! w-full rounded-lg! border-neutral-200! bg-white! py-0! pr-3! pl-8! t
</div>
<div class="overflow-x-auto">
<div
class="grid min-w-[680px] grid-cols-[minmax(10rem,.8fr)_minmax(10rem,.8fr)_minmax(12rem,1fr)_8rem] 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.025] dark:text-fg-faint">
class="grid min-w-[680px] grid-cols-[minmax(10rem,.8fr)_minmax(10rem,.8fr)_minmax(12rem,1fr)_8rem] 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>Project</div>
<div>Environment</div>
<div>Resource</div>

View file

@ -124,7 +124,7 @@ class="h-8! w-full rounded-lg! border-neutral-200! bg-white! py-0! pr-3! pl-8! t
</div>
<div class="overflow-x-auto">
<div
class="grid min-w-[680px] grid-cols-[minmax(10rem,.8fr)_minmax(10rem,.8fr)_minmax(12rem,1fr)_8rem] 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.025] dark:text-fg-faint">
class="grid min-w-[680px] grid-cols-[minmax(10rem,.8fr)_minmax(10rem,.8fr)_minmax(12rem,1fr)_8rem] 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>Project</div>
<div>Environment</div>
<div>Resource</div>

View file

@ -48,7 +48,7 @@ class="button button-highlighted">
<div x-cloak x-show="viewMode === 'grid'" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($s3 as $storage)
<a x-show="matches(@js([$storage->name, $storage->description ?: 'S3-compatible storage', $storage->is_usable ? 'Connected' : 'Not usable']))" {{ wireNavigate() }} href="/storages/{{ $storage->uuid }}"
class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex items-start gap-3">
<div
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim">
@ -74,8 +74,8 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
</a>
@endforeach
</div>
<div x-show="viewMode === 'table'" class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.8fr)_9rem] 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.025] dark:text-fg-faint"><div>Storage</div><div>Description</div><div>Status</div></div>
<div x-show="viewMode === 'table'" class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.8fr)_9rem] 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>Storage</div><div>Description</div><div>Status</div></div>
@foreach ($s3 as $storage)
<a x-show="matches(@js([$storage->name, $storage->description ?: 'S3-compatible storage', $storage->is_usable ? 'Connected' : 'Not usable']))" {{ wireNavigate() }} href="/storages/{{ $storage->uuid }}" class="grid min-h-14 min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.8fr)_9rem] items-center border-b border-neutral-200 px-4 py-2.5 text-[12px] transition-colors last:border-b-0 hover:bg-neutral-50 hover:no-underline dark:border-white/[0.07] dark:hover:bg-white/[0.025]">
<div class="truncate font-semibold text-black dark:text-fg">{{ $storage->name }}</div>

View file

@ -17,7 +17,7 @@ class="h-8! w-full rounded-lg! border-neutral-200! bg-white! py-0! pr-3! pl-8! t
<div class="overflow-x-auto">
<div
class="grid min-w-[780px] grid-cols-[minmax(12rem,1fr)_9rem_7rem_minmax(15rem,1.2fr)] 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.025] dark:text-fg-faint">
class="grid min-w-[780px] grid-cols-[minmax(12rem,1fr)_9rem_7rem_minmax(15rem,1.2fr)] 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>Backup target</div>
<div>Frequency</div>
<div>Status</div>

View file

@ -23,7 +23,7 @@ class="app-tab h-6! px-2.5!"
<div class="grid gap-6 lg:grid-cols-[minmax(0,.8fr)_minmax(0,1.2fr)]">
<div
class="rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="rounded-[10px] border border-neutral-200 bg-neutral-50 p-4 dark:border-white/[0.08] dark:bg-white/[0.05]">
<p class="text-[11px] font-medium text-neutral-500 dark:text-fg-faint">Base price</p>
<div class="mt-2 flex items-end gap-1.5">
<span x-show="selected === 'monthly'" x-cloak

View file

@ -8,7 +8,7 @@
@else
<div class="data-table w-full">
<div
class="grid grid-cols-[minmax(0,1fr)_minmax(8rem,.55fr)_8rem] 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.025] dark:text-fg-faint">
class="grid grid-cols-[minmax(0,1fr)_minmax(8rem,.55fr)_8rem] 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">
<span>Resource</span>
<span>Server</span>
<span>Status</span>

View file

@ -96,7 +96,7 @@ class="flex size-7.5 items-center justify-center rounded-md transition-colors"
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
<template x-for="tag in paginatedTags" :key="tag.id">
<article
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group relative flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<a :href="tag.href" {{ wireNavigate() }} class="absolute inset-0 rounded-xl"
:aria-label="`Open ${tag.name}`"></a>
@ -121,15 +121,15 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
</article>
</template>
</div>
<x-client-pagination x-show="filteredTags.length > 0" class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]"
<x-client-pagination x-show="filteredTags.length > 0" class="mt-3 rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]"
summary="`${rangeStart}-${rangeEnd} of ${filteredTags.length}`" page-size-model="pageSize"
storage-key="coolify.page-size.tags" :options="[12, 24, 48, 96]" />
</div>
<div x-show="viewMode === 'table'"
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
class="overflow-hidden rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div
class="tags-table-grid 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.025] dark:text-fg-faint">
class="tags-table-grid 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>Tag</div>
<div>Resources</div>
<div>Applications</div>
@ -161,7 +161,7 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
</div>
<div x-show="filteredTags.length === 0"
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.025]">
class="flex min-h-52 flex-col items-center justify-center rounded-xl border border-neutral-200 bg-white px-6 text-center dark:border-white/[0.08] dark:bg-white/[0.05]">
<x-reicon name="search" class="mb-3 size-6 text-neutral-300 dark:text-fg-faint" />
<p class="text-[13px] font-medium">No matching tags</p>
<p class="mt-1 text-[12px] text-neutral-500 dark:text-fg-dim">
@ -250,7 +250,7 @@ function tagsIndex() {
<div class="flex flex-col gap-6">
<div class="grid grid-cols-1 gap-3 sm:grid-cols-3">
<div
class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08] dark:bg-white/[0.05]">
<p class="text-[11px] font-medium text-neutral-500 dark:text-fg-faint">Resources</p>
<p class="mt-1 text-[20px] font-semibold tracking-tight text-black dark:text-fg">
{{ $resourceCount }}
@ -260,7 +260,7 @@ class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08
</p>
</div>
<div
class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08] dark:bg-white/[0.05]">
<p class="text-[11px] font-medium text-neutral-500 dark:text-fg-faint">Applications</p>
<p class="mt-1 text-[20px] font-semibold tracking-tight text-black dark:text-fg">
{{ $applications?->count() ?? 0 }}
@ -270,7 +270,7 @@ class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08
</p>
</div>
<div
class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08] dark:bg-white/[0.025]">
class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08] dark:bg-white/[0.05]">
<p class="text-[11px] font-medium text-neutral-500 dark:text-fg-faint">Active deployments</p>
<p class="mt-1 text-[20px] font-semibold tracking-tight text-black dark:text-fg">
{{ collect($deploymentsPerTagPerServer ?? [])->flatten(1)->count() }}
@ -308,7 +308,7 @@ class="rounded-xl border border-neutral-200 bg-white p-3 dark:border-white/[0.08
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($applications ?? [] as $application)
<a {{ wireNavigate() }} href="{{ $application->link() }}"
class="group flex min-h-24 flex-col rounded-lg border border-neutral-200 bg-neutral-50/70 p-3 transition-colors hover:border-neutral-300 hover:no-underline dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-24 flex-col rounded-lg border border-neutral-200 bg-neutral-50/70 p-3 transition-colors hover:border-neutral-300 hover:no-underline dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex items-start gap-2.5">
<div
class="flex size-7 shrink-0 items-center justify-center rounded-md border border-neutral-200 bg-white text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.035] dark:text-fg-dim">
@ -332,7 +332,7 @@ class="truncate text-[12px]! leading-4! font-semibold! text-black dark:text-fg">
@foreach ($services ?? [] as $service)
<a {{ wireNavigate() }} href="{{ $service->link() }}"
class="group flex min-h-24 flex-col rounded-lg border border-neutral-200 bg-neutral-50/70 p-3 transition-colors hover:border-neutral-300 hover:no-underline dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]">
class="group flex min-h-24 flex-col rounded-lg border border-neutral-200 bg-neutral-50/70 p-3 transition-colors hover:border-neutral-300 hover:no-underline dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]">
<div class="flex items-start gap-2.5">
<div
class="flex size-7 shrink-0 items-center justify-center rounded-md border border-neutral-200 bg-white text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.035] dark:text-fg-dim">
@ -374,7 +374,7 @@ class="truncate text-[12px]! leading-4! font-semibold! text-black dark:text-fg">
</div>
@else
<div
class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.55fr)_7rem] 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.025] dark:text-fg-faint">
class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.55fr)_7rem] 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>Server</div>
<div>Status</div>

View file

@ -215,7 +215,7 @@ class="terminal-session-target-trigger flex h-8 min-w-0 max-w-sm cursor-pointer
</button>
<div x-cloak x-show="targetOpen" x-transition.origin.top.left
class="terminal-target-picker absolute top-11 left-0 z-50 w-80 overflow-hidden rounded-lg border shadow-[0_18px_50px_rgba(0,0,0,0.35)]">
class="terminal-target-picker absolute top-11 left-0 z-50 w-80 overflow-hidden rounded-lg border shadow-[var(--shadow-dropdown)]">
<div class="border-b border-white/[0.08] p-1.5">
<div class="relative">
<x-reicon name="search"
@ -287,7 +287,7 @@ class="px-2 py-5 text-center text-[11px] text-white/35">
@else
<div x-cloak x-show="!targetChosen" data-terminal-target-picker="launcher"
class="absolute inset-0 z-20 flex items-start justify-start p-6 sm:p-10">
<div class="terminal-target-picker w-full max-w-md overflow-hidden rounded-lg border shadow-[0_18px_50px_rgba(0,0,0,0.28)]">
<div class="terminal-target-picker w-full max-w-md overflow-hidden rounded-lg border shadow-[var(--shadow-dropdown)]">
<div class="border-b border-white/[0.08] p-2">
<div class="px-1 pb-2">
<div class="text-sm font-semibold text-white/80">Start a terminal session</div>

View file

@ -75,7 +75,7 @@ class="listbox-option justify-start! gap-2.5!" role="menuitem">
<div x-cloak x-show="viewMode === 'grid'" class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($sources as $source)
@if ($source->getMorphClass() === 'App\Models\GithubApp')
<a x-show="matches(@js([$source->name, 'GitHub', $source->organization, $source->isConnected() ? 'Connected' : 'Setup incomplete']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a x-show="matches(@js([$source->name, 'GitHub', $source->organization, $source->isConnected() ? 'Connected' : 'Setup incomplete']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}
href="{{ route('source.github.show', ['github_app_uuid' => data_get($source, 'uuid')]) }}">
<div class="flex items-start gap-3">
@ -102,7 +102,7 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
</div>
</a>
@elseif ($source->getMorphClass() === 'App\Models\GitlabApp')
<a x-show="matches(@js([$source->name, 'GitLab', $source->group_name, $source->isConnected() ? 'Connected' : 'Setup incomplete']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.025] dark:hover:border-white/[0.14]"
<a x-show="matches(@js([$source->name, 'GitLab', $source->group_name, $source->isConnected() ? 'Connected' : 'Setup incomplete']))" class="group flex min-h-28 flex-col rounded-xl border border-neutral-200 bg-white p-3 shadow-sm transition-all hover:-translate-y-px hover:border-neutral-300 hover:no-underline hover:shadow-md dark:border-white/[0.08] dark:bg-white/[0.05] dark:hover:border-white/[0.14]"
{{ wireNavigate() }}
href="{{ route('source.gitlab.show', ['gitlab_app_uuid' => data_get($source, 'uuid')]) }}">
<div class="flex items-start gap-3">
@ -131,8 +131,8 @@ class="flex size-8 shrink-0 items-center justify-center rounded-lg border border
@endif
@endforeach
</div>
<div x-show="viewMode === 'table'" class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.025]">
<div class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.7fr)_9rem] 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.025] dark:text-fg-faint"><div>Source</div><div>Provider</div><div>Status</div></div>
<div x-show="viewMode === 'table'" class="overflow-x-auto rounded-xl border border-neutral-200 bg-white shadow-sm dark:border-white/[0.08] dark:bg-white/[0.05]">
<div class="grid min-w-[620px] grid-cols-[minmax(0,1fr)_minmax(10rem,.7fr)_9rem] 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>Source</div><div>Provider</div><div>Status</div></div>
@foreach ($sources as $source)
@php
$isGithub = $source->getMorphClass() === 'App\\Models\\GithubApp';