diff --git a/app/assets/stylesheets/solid_queue_web/_01_base.css b/app/assets/stylesheets/solid_queue_web/_01_base.css new file mode 100644 index 0000000..3635e0d --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_01_base.css @@ -0,0 +1,41 @@ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +.sqd-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +:focus-visible { + outline: 2px solid var(--primary); + outline-offset: 2px; + border-radius: 2px; +} + +:root { + --bg: #f8f9fa; + --surface: #ffffff; + --border: #dee2e6; + --text: #212529; + --muted: #6c757d; + --primary: #0d6efd; + --danger: #dc3545; + --warning: #fd7e14; + --success: #198754; + --info: #0dcaf0; + --purple: #6f42c1; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + font-size: 14px; + background: var(--bg); + color: var(--text); + line-height: 1.5; +} diff --git a/app/assets/stylesheets/solid_queue_web/_02_layout.css b/app/assets/stylesheets/solid_queue_web/_02_layout.css new file mode 100644 index 0000000..fe3dda1 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_02_layout.css @@ -0,0 +1,99 @@ +.sqd-header { + background: var(--surface); + border-bottom: 1px solid var(--border); +} + +.sqd-header__inner { + max-width: 1200px; + margin: 0 auto; + padding: 0 1.5rem; + display: flex; + align-items: center; + gap: 2rem; + height: 56px; +} + +.sqd-header__title { + font-size: 16px; + font-weight: 600; + color: var(--text); + text-decoration: none; +} + +.sqd-nav { + display: flex; + gap: 0.25rem; + list-style: none; +} + +.sqd-nav a { + display: block; + padding: 0.35rem 0.75rem; + border-radius: 6px; + color: var(--muted); + text-decoration: none; + font-size: 13px; + font-weight: 500; + transition: background 0.1s, color 0.1s; +} + +.sqd-nav a:hover, +.sqd-nav a.active { + background: var(--bg); + color: var(--text); +} + +.sqd-nav-toggle { + display: none; + flex-direction: column; + justify-content: center; + gap: 5px; + width: 36px; + height: 36px; + padding: 6px; + margin-left: auto; + background: none; + border: 1px solid var(--border); + border-radius: 5px; + cursor: pointer; +} + +.sqd-nav-toggle span { + display: block; + height: 2px; + background: var(--text); + border-radius: 1px; +} + +.sqd-main { + max-width: 1200px; + margin: 0 auto; + padding: 2rem 1.5rem; +} + +.sqd-page-title { + font-size: 20px; + font-weight: 600; + margin-bottom: 0; +} + +.sqd-page-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1.5rem; +} + +.sqd-actions { + display: flex; + gap: 0.5rem; +} + +.sqd-flash { + padding: 0.75rem 1rem; + border-radius: 6px; + margin-bottom: 1rem; + font-size: 13px; +} +.sqd-flash--notice { background: #d1e7dd; color: #0f5132; border: 1px solid #badbcc; } +.sqd-flash--alert { background: #f8d7da; color: #842029; border: 1px solid #f5c2c7; } \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_03_stats.css b/app/assets/stylesheets/solid_queue_web/_03_stats.css new file mode 100644 index 0000000..f24c4b3 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_03_stats.css @@ -0,0 +1,49 @@ +.sqd-stats { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} + +.sqd-stat { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 8px; + padding: 1.25rem 1rem; + text-align: center; +} + +.sqd-stat__value { + font-size: 28px; + font-weight: 700; + line-height: 1; + margin-bottom: 0.25rem; +} + +.sqd-stat__label { + font-size: 12px; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.sqd-stat--ready .sqd-stat__value { color: var(--success); } +.sqd-stat--scheduled .sqd-stat__value { color: var(--info); } +.sqd-stat--claimed .sqd-stat__value { color: var(--primary); } +.sqd-stat--failed .sqd-stat__value { color: var(--danger); } +.sqd-stat--blocked .sqd-stat__value { color: var(--warning); } +.sqd-stat--queues .sqd-stat__value { color: var(--purple); } +.sqd-stat--processes .sqd-stat__value { color: var(--muted); } +.sqd-stat--recurring .sqd-stat__value { color: var(--info); } + +.sqd-stat--link { + display: block; + text-decoration: none; + color: inherit; + transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; +} +.sqd-stat--link:hover { + border-color: var(--primary); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transform: translateY(-2px); +} \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_04_table.css b/app/assets/stylesheets/solid_queue_web/_04_table.css new file mode 100644 index 0000000..8ba8488 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_04_table.css @@ -0,0 +1,52 @@ +.sqd-card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 8px; + overflow: hidden; +} + +.sqd-card__header { + padding: 0.875rem 1rem; + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.sqd-card__title { + font-size: 14px; + font-weight: 600; +} + +table { + width: 100%; + border-collapse: collapse; +} + +th { + padding: 0.625rem 1rem; + text-align: left; + font-size: 12px; + font-weight: 600; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.05em; + border-bottom: 1px solid var(--border); + white-space: nowrap; +} + +td { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--border); + vertical-align: middle; +} + +tr:last-child td { border-bottom: none; } +tbody tr:hover { background: var(--bg); } + +.sqd-empty { + text-align: center; + padding: 3rem 1rem; + color: var(--muted); +} \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_05_badges.css b/app/assets/stylesheets/solid_queue_web/_05_badges.css new file mode 100644 index 0000000..1c5e3fd --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_05_badges.css @@ -0,0 +1,27 @@ +.sqd-badge { + display: inline-block; + padding: 0.2em 0.55em; + border-radius: 4px; + font-size: 11px; + font-weight: 600; + line-height: 1; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.sqd-badge--ready { background: #d1e7dd; color: #0f5132; } +.sqd-badge--scheduled { background: #cff4fc; color: #055160; } +.sqd-badge--claimed { background: #cfe2ff; color: #084298; } +.sqd-badge--failed { background: #f8d7da; color: #842029; } +.sqd-badge--blocked { background: #fff3cd; color: #664d03; } +.sqd-badge--static { background: #d1e7dd; color: #0f5132; } +.sqd-badge--dynamic { background: #e0d7f5; color: #4a2c8a; } +.sqd-badge--paused { background: #e2e3e5; color: #41464b; } +.sqd-badge--running { background: #d1e7dd; color: #0f5132; } +.sqd-badge--supervisor { background: #e0d7f5; color: #4a2c8a; } +.sqd-badge--worker { background: #d1e7dd; color: #0f5132; } +.sqd-badge--dispatcher { background: #cff4fc; color: #055160; } + +.sqd-process-meta { font-size: 12px; color: var(--muted); } +.sqd-process-meta span + span::before { content: " · "; } +.sqd-muted-text { color: var(--muted); font-size: 13px; } \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_06_buttons.css b/app/assets/stylesheets/solid_queue_web/_06_buttons.css new file mode 100644 index 0000000..c5efc77 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_06_buttons.css @@ -0,0 +1,38 @@ +.sqd-btn { + display: inline-flex; + align-items: center; + padding: 0.35rem 0.75rem; + border-radius: 5px; + font-size: 12px; + font-weight: 500; + text-decoration: none; + border: 1px solid transparent; + cursor: pointer; + transition: opacity 0.15s; +} +.sqd-btn:hover { opacity: 0.85; } +.sqd-btn--primary { background: var(--primary); color: #fff; border-color: var(--primary); } +.sqd-btn--danger { background: var(--danger); color: #fff; border-color: var(--danger); } +.sqd-btn--muted { background: var(--surface); color: var(--text); border-color: var(--border); } +.sqd-btn--sm { padding: 0.2rem 0.55rem; font-size: 11px; } + +.sqd-row-actions { white-space: nowrap; text-align: right; width: 1%; } +.sqd-row-actions form { display: inline; margin-left: 0.25rem; } + +.sqd-selection-bar { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 1rem; + background: var(--bg); + border-bottom: 1px solid var(--border); + font-size: 13px; +} + +table th input[type="checkbox"], +table td input[type="checkbox"] { + width: 15px; + height: 15px; + cursor: pointer; + accent-color: var(--primary); +} \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_07_forms.css b/app/assets/stylesheets/solid_queue_web/_07_forms.css new file mode 100644 index 0000000..6903ae0 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_07_forms.css @@ -0,0 +1,103 @@ +.sqd-search { + display: flex; + gap: 0.5rem; + align-items: center; + margin-bottom: 1rem; +} + +.sqd-search__input { + width: 280px; + padding: 0.35rem 0.75rem; + border: 1px solid var(--border); + border-radius: 5px; + font-size: 13px; + background: var(--surface); + color: var(--text); + line-height: 1.5; +} + +.sqd-search__input:focus { + outline: 2px solid var(--primary); + outline-offset: -1px; + border-color: var(--primary); +} + +@media (max-width: 640px) { + .sqd-search { flex-wrap: wrap; } + .sqd-search__input { width: 100%; } +} + +.sqd-search--global { margin-bottom: 2rem; } + +.sqd-search__input--lg { + width: 420px; + font-size: 15px; + padding: 0.5rem 1rem; +} + +@media (max-width: 640px) { + .sqd-search__input--lg { width: 100%; } +} + +.sqd-search-group { + margin-bottom: 2rem; +} + +.sqd-search-group__header { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 0.75rem; +} + +.sqd-filters { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + margin-bottom: 1rem; +} + +.sqd-filters a { + padding: 0.35rem 0.875rem; + border-radius: 20px; + font-size: 12px; + font-weight: 500; + text-decoration: none; + border: 1px solid var(--border); + color: var(--muted); + background: var(--surface); + transition: all 0.1s; +} + +.sqd-filters a:hover, +.sqd-filters a.active { + background: var(--primary); + border-color: var(--primary); + color: #fff; +} + +.sqd-period-filter { + display: flex; + align-items: center; + gap: 0.25rem; + margin-left: auto; +} + +.sqd-period-filter a { + padding: 0.2rem 0.55rem; + border-radius: 4px; + font-size: 11px; + font-weight: 500; + text-decoration: none; + border: 1px solid var(--border); + color: var(--muted); + background: var(--surface); + transition: all 0.1s; +} + +.sqd-period-filter a:hover, +.sqd-period-filter a.active { + background: var(--muted); + border-color: var(--muted); + color: #fff; +} \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_08_detail.css b/app/assets/stylesheets/solid_queue_web/_08_detail.css new file mode 100644 index 0000000..7425d0a --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_08_detail.css @@ -0,0 +1,84 @@ +.sqd-mono { + font-family: "SFMono-Regular", Menlo, Monaco, Consolas, monospace; + font-size: 12px; +} + +.sqd-error-msg { + color: var(--danger); + font-size: 12px; +} + +.sqd-truncate { + max-width: 320px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sqd-detail-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +.sqd-grid-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} + +.sqd-breadcrumb { + font-size: 12px; + color: var(--muted); + margin-bottom: 0.25rem; +} + +.sqd-breadcrumb a { color: var(--muted); text-decoration: none; } +.sqd-breadcrumb a:hover { color: var(--text); } + +.sqd-detail-section { padding: 1.25rem; } + +.sqd-section-title { + font-size: 13px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--muted); + margin-bottom: 1rem; +} + +.sqd-section-title--danger { color: var(--danger); } + +.sqd-dl { + display: grid; + grid-template-columns: auto 1fr; + gap: 0.5rem 1.5rem; + font-size: 13px; +} + +.sqd-dl dt { color: var(--muted); white-space: nowrap; } +.sqd-dl dd { word-break: break-all; } + +.sqd-pre { + font-family: monospace; + font-size: 12px; + background: var(--bg); + border: 1px solid var(--border); + border-radius: 5px; + padding: 0.75rem; + overflow-x: auto; + white-space: pre-wrap; + word-break: break-word; + max-height: 400px; + overflow-y: auto; +} + +.sqd-pre--muted { color: var(--muted); } + +.sqd-error-header { + font-size: 13px; + padding: 0.5rem 0.75rem; + background: #f8d7da; + color: #842029; + border-radius: 5px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_09_pagination.css b/app/assets/stylesheets/solid_queue_web/_09_pagination.css new file mode 100644 index 0000000..8260f91 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_09_pagination.css @@ -0,0 +1,27 @@ +nav.pagy { + display: flex; + justify-content: center; + gap: 0.25rem; + padding: 1rem; + list-style: none; +} + +nav.pagy a { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 32px; + height: 32px; + padding: 0 0.5rem; + border-radius: 5px; + font-size: 13px; + text-decoration: none; + border: 1px solid var(--border); + color: var(--text); + background: var(--surface); +} + +nav.pagy a:hover:not([aria-disabled="true"]) { background: var(--bg); } +nav.pagy a[aria-current="page"] { background: var(--primary); color: #fff; border-color: var(--primary); } +nav.pagy a[role="separator"], +nav.pagy a[aria-disabled="true"] { color: var(--muted); cursor: default; } \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/_10_responsive.css b/app/assets/stylesheets/solid_queue_web/_10_responsive.css new file mode 100644 index 0000000..f00e264 --- /dev/null +++ b/app/assets/stylesheets/solid_queue_web/_10_responsive.css @@ -0,0 +1,73 @@ +@media (max-width: 768px) { + .sqd-detail-grid { grid-template-columns: 1fr; } + .sqd-grid-2 { grid-template-columns: 1fr; } +} + +@media (max-width: 640px) { + .sqd-main { + padding: 1.5rem 1rem; + } + + .sqd-page-header { + flex-direction: column; + align-items: flex-start; + gap: 0.75rem; + } + + .sqd-card { + overflow-x: auto; + } + + .sqd-card__header { + flex-wrap: wrap; + } + + .sqd-stats { + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + } + + .sqd-truncate { + max-width: 160px; + } +} + +@media (max-width: 576px) { + .sqd-header { + position: relative; + } + + .sqd-header__inner { + padding: 0 1rem; + } + + .sqd-nav-toggle { + display: flex; + } + + .sqd-nav-wrapper { + display: none; + position: absolute; + top: 100%; + left: 0; + right: 0; + background: var(--surface); + border-bottom: 1px solid var(--border); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + z-index: 50; + padding: 0.5rem; + } + + .sqd-nav-wrapper.sqd-nav--open { + display: block; + } + + .sqd-nav { + flex-direction: column; + gap: 0.25rem; + } + + .sqd-nav a { + padding: 0.5rem 0.75rem; + font-size: 14px; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/solid_queue_web/application.css b/app/assets/stylesheets/solid_queue_web/application.css index 031b15b..17aae64 100644 --- a/app/assets/stylesheets/solid_queue_web/application.css +++ b/app/assets/stylesheets/solid_queue_web/application.css @@ -1,619 +1,3 @@ /* *= require_self - */ - -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - -.sqd-sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -:focus-visible { - outline: 2px solid var(--primary); - outline-offset: 2px; - border-radius: 2px; -} - -:root { - --bg: #f8f9fa; - --surface: #ffffff; - --border: #dee2e6; - --text: #212529; - --muted: #6c757d; - --primary: #0d6efd; - --danger: #dc3545; - --warning: #fd7e14; - --success: #198754; - --info: #0dcaf0; - --purple: #6f42c1; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - font-size: 14px; - background: var(--bg); - color: var(--text); - line-height: 1.5; -} - -/* Layout */ -.sqd-header { - background: var(--surface); - border-bottom: 1px solid var(--border); -} - -.sqd-header__inner { - max-width: 1200px; - margin: 0 auto; - padding: 0 1.5rem; - display: flex; - align-items: center; - gap: 2rem; - height: 56px; -} - -.sqd-header__title { - font-size: 16px; - font-weight: 600; - color: var(--text); - text-decoration: none; -} - -.sqd-nav { - display: flex; - gap: 0.25rem; - list-style: none; -} - -.sqd-nav a { - display: block; - padding: 0.35rem 0.75rem; - border-radius: 6px; - color: var(--muted); - text-decoration: none; - font-size: 13px; - font-weight: 500; - transition: background 0.1s, color 0.1s; -} - -.sqd-nav a:hover, -.sqd-nav a.active { - background: var(--bg); - color: var(--text); -} - -.sqd-nav-toggle { - display: none; - flex-direction: column; - justify-content: center; - gap: 5px; - width: 36px; - height: 36px; - padding: 6px; - margin-left: auto; - background: none; - border: 1px solid var(--border); - border-radius: 5px; - cursor: pointer; -} - -.sqd-nav-toggle span { - display: block; - height: 2px; - background: var(--text); - border-radius: 1px; -} - -.sqd-main { - max-width: 1200px; - margin: 0 auto; - padding: 2rem 1.5rem; -} - -.sqd-page-title { - font-size: 20px; - font-weight: 600; - margin-bottom: 0; -} - -.sqd-page-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 1.5rem; -} - -.sqd-actions { - display: flex; - gap: 0.5rem; -} - -/* Flash notices */ -.sqd-flash { - padding: 0.75rem 1rem; - border-radius: 6px; - margin-bottom: 1rem; - font-size: 13px; -} -.sqd-flash--notice { background: #d1e7dd; color: #0f5132; border: 1px solid #badbcc; } -.sqd-flash--alert { background: #f8d7da; color: #842029; border: 1px solid #f5c2c7; } - -/* Stat cards */ -.sqd-stats { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); - gap: 1rem; - margin-bottom: 2rem; -} - -.sqd-stat { - background: var(--surface); - border: 1px solid var(--border); - border-radius: 8px; - padding: 1.25rem 1rem; - text-align: center; -} - -.sqd-stat__value { - font-size: 28px; - font-weight: 700; - line-height: 1; - margin-bottom: 0.25rem; -} - -.sqd-stat__label { - font-size: 12px; - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.sqd-stat--ready .sqd-stat__value { color: var(--success); } -.sqd-stat--scheduled .sqd-stat__value { color: var(--info); } -.sqd-stat--claimed .sqd-stat__value { color: var(--primary); } -.sqd-stat--failed .sqd-stat__value { color: var(--danger); } -.sqd-stat--blocked .sqd-stat__value { color: var(--warning); } -.sqd-stat--queues .sqd-stat__value { color: var(--purple); } -.sqd-stat--processes .sqd-stat__value { color: var(--muted); } -.sqd-stat--recurring .sqd-stat__value { color: var(--info); } - -.sqd-stat--link { - display: block; - text-decoration: none; - color: inherit; - transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; -} -.sqd-stat--link:hover { - border-color: var(--primary); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); - transform: translateY(-2px); -} - -/* Tables */ -.sqd-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: 8px; - overflow: hidden; -} - -.sqd-card__header { - padding: 0.875rem 1rem; - border-bottom: 1px solid var(--border); - display: flex; - align-items: center; - justify-content: space-between; - gap: 1rem; -} - -.sqd-card__title { - font-size: 14px; - font-weight: 600; -} - -table { - width: 100%; - border-collapse: collapse; -} - -th { - padding: 0.625rem 1rem; - text-align: left; - font-size: 12px; - font-weight: 600; - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.05em; - border-bottom: 1px solid var(--border); - white-space: nowrap; -} - -td { - padding: 0.75rem 1rem; - border-bottom: 1px solid var(--border); - vertical-align: middle; -} - -tr:last-child td { border-bottom: none; } -tbody tr:hover { background: var(--bg); } - -.sqd-empty { - text-align: center; - padding: 3rem 1rem; - color: var(--muted); -} - -/* Badges */ -.sqd-badge { - display: inline-block; - padding: 0.2em 0.55em; - border-radius: 4px; - font-size: 11px; - font-weight: 600; - line-height: 1; - text-transform: uppercase; - letter-spacing: 0.04em; -} - -.sqd-badge--ready { background: #d1e7dd; color: #0f5132; } -.sqd-badge--scheduled { background: #cff4fc; color: #055160; } -.sqd-badge--claimed { background: #cfe2ff; color: #084298; } -.sqd-badge--failed { background: #f8d7da; color: #842029; } -.sqd-badge--blocked { background: #fff3cd; color: #664d03; } -.sqd-badge--static { background: #d1e7dd; color: #0f5132; } -.sqd-badge--dynamic { background: #e0d7f5; color: #4a2c8a; } -.sqd-badge--paused { background: #e2e3e5; color: #41464b; } -.sqd-badge--running { background: #d1e7dd; color: #0f5132; } -.sqd-badge--supervisor { background: #e0d7f5; color: #4a2c8a; } -.sqd-badge--worker { background: #d1e7dd; color: #0f5132; } -.sqd-badge--dispatcher { background: #cff4fc; color: #055160; } - -.sqd-process-meta { font-size: 12px; color: var(--muted); } -.sqd-process-meta span + span::before { content: " · "; } -.sqd-muted-text { color: var(--muted); font-size: 13px; } - -/* Buttons */ -.sqd-btn { - display: inline-flex; - align-items: center; - padding: 0.35rem 0.75rem; - border-radius: 5px; - font-size: 12px; - font-weight: 500; - text-decoration: none; - border: 1px solid transparent; - cursor: pointer; - transition: opacity 0.15s; -} -.sqd-btn:hover { opacity: 0.85; } -.sqd-btn--primary { background: var(--primary); color: #fff; border-color: var(--primary); } -.sqd-btn--danger { background: var(--danger); color: #fff; border-color: var(--danger); } -.sqd-btn--muted { background: var(--surface); color: var(--text); border-color: var(--border); } -.sqd-btn--sm { padding: 0.2rem 0.55rem; font-size: 11px; } - -.sqd-row-actions { white-space: nowrap; text-align: right; width: 1%; } -.sqd-row-actions form { display: inline; margin-left: 0.25rem; } - -/* Selection bar */ -.sqd-selection-bar { - display: flex; - align-items: center; - gap: 0.75rem; - padding: 0.5rem 1rem; - background: var(--bg); - border-bottom: 1px solid var(--border); - font-size: 13px; -} - -table th input[type="checkbox"], -table td input[type="checkbox"] { - width: 15px; - height: 15px; - cursor: pointer; - accent-color: var(--primary); -} - -/* Search */ -.sqd-search { - display: flex; - gap: 0.5rem; - align-items: center; - margin-bottom: 1rem; -} - -.sqd-search__input { - width: 280px; - padding: 0.35rem 0.75rem; - border: 1px solid var(--border); - border-radius: 5px; - font-size: 13px; - background: var(--surface); - color: var(--text); - line-height: 1.5; -} - -.sqd-search__input:focus { - outline: 2px solid var(--primary); - outline-offset: -1px; - border-color: var(--primary); -} - -@media (max-width: 640px) { - .sqd-search { flex-wrap: wrap; } - .sqd-search__input { width: 100%; } -} - -.sqd-search--global { margin-bottom: 2rem; } - -.sqd-search__input--lg { - width: 420px; - font-size: 15px; - padding: 0.5rem 1rem; -} - -@media (max-width: 640px) { - .sqd-search__input--lg { width: 100%; } -} - -.sqd-search-group { - margin-bottom: 2rem; -} - -.sqd-search-group__header { - display: flex; - align-items: center; - gap: 0.75rem; - margin-bottom: 0.75rem; -} - -/* Filters */ -.sqd-filters { - display: flex; - gap: 0.5rem; - flex-wrap: wrap; - margin-bottom: 1rem; -} - -.sqd-filters a { - padding: 0.35rem 0.875rem; - border-radius: 20px; - font-size: 12px; - font-weight: 500; - text-decoration: none; - border: 1px solid var(--border); - color: var(--muted); - background: var(--surface); - transition: all 0.1s; -} - -.sqd-filters a:hover, -.sqd-filters a.active { - background: var(--primary); - border-color: var(--primary); - color: #fff; -} - -/* Period filter */ -.sqd-period-filter { - display: flex; - align-items: center; - gap: 0.25rem; - margin-left: auto; -} - -.sqd-period-filter a { - padding: 0.2rem 0.55rem; - border-radius: 4px; - font-size: 11px; - font-weight: 500; - text-decoration: none; - border: 1px solid var(--border); - color: var(--muted); - background: var(--surface); - transition: all 0.1s; -} - -.sqd-period-filter a:hover, -.sqd-period-filter a.active { - background: var(--muted); - border-color: var(--muted); - color: #fff; -} - -/* Code / monospace */ -.sqd-mono { - font-family: "SFMono-Regular", Menlo, Monaco, Consolas, monospace; - font-size: 12px; -} - -.sqd-error-msg { - color: var(--danger); - font-size: 12px; -} - -.sqd-truncate { - max-width: 320px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* Pagination (pagy v43 series-nav) */ -nav.pagy { - display: flex; - justify-content: center; - gap: 0.25rem; - padding: 1rem; - list-style: none; -} - -nav.pagy a { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 32px; - height: 32px; - padding: 0 0.5rem; - border-radius: 5px; - font-size: 13px; - text-decoration: none; - border: 1px solid var(--border); - color: var(--text); - background: var(--surface); -} - -nav.pagy a:hover:not([aria-disabled="true"]) { background: var(--bg); } -nav.pagy a[aria-current="page"] { background: var(--primary); color: #fff; border-color: var(--primary); } -nav.pagy a[role="separator"], -nav.pagy a[aria-disabled="true"] { color: var(--muted); cursor: default; } - -/* Job detail page */ -.sqd-breadcrumb { - font-size: 12px; - color: var(--muted); - margin-bottom: 0.25rem; -} - -.sqd-breadcrumb a { color: var(--muted); text-decoration: none; } -.sqd-breadcrumb a:hover { color: var(--text); } - -.sqd-detail-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1.5rem; -} - -.sqd-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; -} - -@media (max-width: 768px) { - .sqd-detail-grid { grid-template-columns: 1fr; } - .sqd-grid-2 { grid-template-columns: 1fr; } -} - -@media (max-width: 640px) { - .sqd-main { - padding: 1.5rem 1rem; - } - - .sqd-page-header { - flex-direction: column; - align-items: flex-start; - gap: 0.75rem; - } - - .sqd-card { - overflow-x: auto; - } - - .sqd-card__header { - flex-wrap: wrap; - } - - .sqd-stats { - grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); - } - - .sqd-truncate { - max-width: 160px; - } -} - -@media (max-width: 576px) { - .sqd-header { - position: relative; - } - - .sqd-header__inner { - padding: 0 1rem; - } - - .sqd-nav-toggle { - display: flex; - } - - .sqd-nav-wrapper { - display: none; - position: absolute; - top: 100%; - left: 0; - right: 0; - background: var(--surface); - border-bottom: 1px solid var(--border); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); - z-index: 50; - padding: 0.5rem; - } - - .sqd-nav-wrapper.sqd-nav--open { - display: block; - } - - .sqd-nav { - flex-direction: column; - gap: 0.25rem; - } - - .sqd-nav a { - padding: 0.5rem 0.75rem; - font-size: 14px; - } -} - -.sqd-detail-section { padding: 1.25rem; } - -.sqd-section-title { - font-size: 13px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; - color: var(--muted); - margin-bottom: 1rem; -} - -.sqd-section-title--danger { color: var(--danger); } - -.sqd-dl { - display: grid; - grid-template-columns: auto 1fr; - gap: 0.5rem 1.5rem; - font-size: 13px; -} - -.sqd-dl dt { color: var(--muted); white-space: nowrap; } -.sqd-dl dd { word-break: break-all; } - -.sqd-pre { - font-family: monospace; - font-size: 12px; - background: var(--bg); - border: 1px solid var(--border); - border-radius: 5px; - padding: 0.75rem; - overflow-x: auto; - white-space: pre-wrap; - word-break: break-word; - max-height: 400px; - overflow-y: auto; -} - -.sqd-pre--muted { color: var(--muted); } - -.sqd-error-header { - font-size: 13px; - padding: 0.5rem 0.75rem; - background: #f8d7da; - color: #842029; - border-radius: 5px; -} \ No newline at end of file + */ \ No newline at end of file diff --git a/app/helpers/solid_queue_web/application_helper.rb b/app/helpers/solid_queue_web/application_helper.rb index 8656b78..3f0957e 100644 --- a/app/helpers/solid_queue_web/application_helper.rb +++ b/app/helpers/solid_queue_web/application_helper.rb @@ -1,7 +1,8 @@ module SolidQueueWeb module ApplicationHelper def inline_styles - css = SolidQueueWeb::Engine.root.join("app/assets/stylesheets/solid_queue_web/application.css").read + dir = SolidQueueWeb::Engine.root.join("app/assets/stylesheets/solid_queue_web") + css = dir.glob("_*.css").sort.map(&:read).join("\n") content_tag(:style, css.html_safe) end end diff --git a/app/javascript/solid_queue_web/refresh_controller.js b/app/javascript/solid_queue_web/refresh_controller.js index f0eedf6..7f62b31 100644 --- a/app/javascript/solid_queue_web/refresh_controller.js +++ b/app/javascript/solid_queue_web/refresh_controller.js @@ -23,7 +23,8 @@ export default class extends Controller { async _reload() { clearTimeout(this._timer) - if (!document.hidden) { + const hasSelection = this.element.querySelector("input[type='checkbox']:checked") + if (!document.hidden && !hasSelection) { try { const response = await fetch(window.location.href, { headers: { "Turbo-Frame": this.element.id, Accept: "text/html" } @@ -44,7 +45,7 @@ export default class extends Controller { _onVisibilityChange() { if (document.hidden) { clearTimeout(this._timer) - } else { + } else if (!this.element.querySelector("input[type='checkbox']:checked")) { this._reload() } }