From 71d1b18314f15518f7ea18e62803533eb1d04e51 Mon Sep 17 00:00:00 2001 From: dm Date: Sat, 13 Dec 2025 12:34:37 +0100 Subject: [PATCH] =?UTF-8?q?Poprawki=20w=20wyszikiwaniu=20kana=C5=82=C3=B3w?= =?UTF-8?q?=20i=20wy=C5=9Bwietlaniu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sections/SectionChannelsSearch.astro | 7 - src/islands/jambox/JamboxChannelsModal.jsx | 23 +- src/islands/jambox/JamboxChannelsSearch.jsx | 32 +- src/pages/api/jambox/channels-search.js | 5 +- src/styles/channels-search.css | 8 +- src/styles/offers/offers-table.css | 508 ++++++++---------- 6 files changed, 266 insertions(+), 317 deletions(-) diff --git a/src/components/sections/SectionChannelsSearch.astro b/src/components/sections/SectionChannelsSearch.astro index 989bbbb..4c8bf8b 100644 --- a/src/components/sections/SectionChannelsSearch.astro +++ b/src/components/sections/SectionChannelsSearch.astro @@ -46,13 +46,6 @@ if (section.image) { - {section.button && ( - - )} diff --git a/src/islands/jambox/JamboxChannelsModal.jsx b/src/islands/jambox/JamboxChannelsModal.jsx index 5749d61..db802f0 100644 --- a/src/islands/jambox/JamboxChannelsModal.jsx +++ b/src/islands/jambox/JamboxChannelsModal.jsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState } from "preact/hooks"; import "../../styles/modal.css"; import "../../styles/offers/offers-table.css"; -import "../../styles/channels-search.css"; // żeby input miał identyczny styl +import "../../styles/channels-search.css"; export default function JamboxChannelsModal({ isOpen, onClose, pkg }) { const [channels, setChannels] = useState([]); @@ -18,9 +18,8 @@ export default function JamboxChannelsModal({ isOpen, onClose, pkg }) { const meta = useMemo(() => { if (loading) return "Ładowanie…"; if (error) return error; - if (!query.trim()) return `Wyniki: ${filtered.length} / ${channels.length}`; return `Wyniki: ${filtered.length} / ${channels.length}`; - }, [loading, error, query, filtered.length, channels.length]); + }, [loading, error, filtered.length, channels.length]); useEffect(() => { if (!isOpen || !pkg?.id) return; @@ -36,7 +35,6 @@ export default function JamboxChannelsModal({ isOpen, onClose, pkg }) { try { const params = new URLSearchParams({ packageId: String(pkg.id) }); const res = await fetch(`/api/jambox/channels?${params.toString()}`); - if (!res.ok) throw new Error(`HTTP ${res.status}`); const json = await res.json(); @@ -81,7 +79,6 @@ export default function JamboxChannelsModal({ isOpen, onClose, pkg }) {

Kanały w pakiecie {pkg.name}

- {/* INPUT jak w wyszukiwarce (z własnym X) */}
setQuery("")} - onMouseDown={(e) => e.preventDefault()} // nie zabieraj focusa inputowi + onMouseDown={(e) => e.preventDefault()} > ✕ )}
+ {/* ✅ tu musi być __meta */}
{meta}
@@ -117,19 +115,25 @@ export default function JamboxChannelsModal({ isOpen, onClose, pkg }) { {filtered.length === 0 ? (

Brak kanałów spełniających kryteria.

) : ( -
+
{filtered.map((ch) => (
{ - // żeby klik w link w opisie nie flipował if (e.target.closest("a, button")) return; e.currentTarget.classList.toggle("is-flipped"); }} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + e.currentTarget.classList.toggle("is-flipped"); + } + }} >
- {/* FRONT */}
{ch.logo_url && ( kanał {ch.number}
- {/* BACK */}
{ch.name}
{ const qq = q.trim(); - if (qq.length < 2) return "Wpisz min. 2 znaki"; + if (qq.length === 0) return ""; + // "Zacznij pisać, aby wyszukać" if (loading) return "Szukam…"; if (err) return err; return `Znaleziono: ${items.length}`; @@ -71,7 +72,7 @@ export default function JamboxChannelsSearch() { el.scrollIntoView({ behavior: "smooth", block: "start" }); el.classList.add("is-target"); - window.setTimeout(() => el.classList.remove("is-target"), 1200); + window.setTimeout(() => el.classList.remove("is-target"), 5400); } return ( @@ -101,7 +102,7 @@ export default function JamboxChannelsSearch() { )}
-
{meta}
+
{meta}
@@ -138,16 +139,19 @@ export default function JamboxChannelsSearch() {
Dostępny w:  {c.packages.map((p, i) => ( - + + {" "} (kanał {p.number}) + {i < c.packages.length - 1 ? ", " : ""} - + ))}
)} @@ -156,7 +160,7 @@ export default function JamboxChannelsSearch() { ))} {q.trim().length >= 2 && !loading && items.length === 0 && ( -
+
Brak wyników dla: {q}
)} diff --git a/src/pages/api/jambox/channels-search.js b/src/pages/api/jambox/channels-search.js index 52dad8b..3a8f87f 100644 --- a/src/pages/api/jambox/channels-search.js +++ b/src/pages/api/jambox/channels-search.js @@ -14,7 +14,7 @@ export function GET({ url }) { const q = (url.searchParams.get("q") || "").trim(); const limit = clamp(Number(url.searchParams.get("limit") || 50), 1, 200); - if (q.length < 2) { + if (q.length < 0) { return new Response(JSON.stringify({ ok: true, data: [] }), { status: 200, headers: { "Content-Type": "application/json; charset=utf-8" }, @@ -27,9 +27,6 @@ export function GET({ url }) { const db = getDb(); try { - // ✅ 1 rekord na kanał (grupujemy po name+logo_url) - // ✅ pakiety zbieramy do jednego pola packages_blob - // UWAGA: zakładam, że jambox_base_packages ma kolumnę "name" const rows = db .prepare( ` diff --git a/src/styles/channels-search.css b/src/styles/channels-search.css index 88beb2c..a3fa8b7 100644 --- a/src/styles/channels-search.css +++ b/src/styles/channels-search.css @@ -27,8 +27,8 @@ @apply opacity-100; } - .f-chsearch__meta { - @apply text-sm opacity-70 pl-1; + .f-chsearch-meta { + @apply text-sm opacity-70 pl-1 ml-2; } /* ========================= @@ -110,8 +110,8 @@ /* ========================= Empty state ========================== */ - .f-chsearch__empty { - @apply mt-2 p-4 rounded-2xl border border-slate-200 dark:border-slate-700 opacity-80; + .f-chsearch-empty { + @apply mt-2 p-4 text-lg; } .f-chsearch__input::-webkit-search-cancel-button { diff --git a/src/styles/offers/offers-table.css b/src/styles/offers/offers-table.css index 2338cee..5ac31da 100644 --- a/src/styles/offers/offers-table.css +++ b/src/styles/offers/offers-table.css @@ -1,333 +1,285 @@ -/* GŁÓWNE SEKCJE */ -.f-offers { - @apply my-6; -} + .f-offers { + @apply my-6; + } -/* GRID FLEX — zawsze centrowany */ -.f-offers-grid { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 2rem; - padding: 0 1rem; -} + /* GRID FLEX — zawsze centrowany */ + .f-offers-grid { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 2rem; + padding: 0 1rem; + } -/* ----------------------------- - KARTA – MOBILE FIRST ------------------------------- */ - -/* MOBILE: każda karta ~pełna szerokość */ -.f-card { - flex: 1 1 100%; - max-width: 26rem; /* możesz dać 100%, jeśli chcesz naprawdę full */ - @apply bg-[--f-bg] text-[--f-text] border border-[--f-offers-border] - rounded-2xl shadow-md p-6 relative flex flex-col gap-4; -} - -.f-card:hover { - @apply shadow-lg; - transform: translateY(-3px); -} - -/* POPULARNY PLAN */ -.f-card-popular { - border: 2px solid var(--f-offers-popular); - background: var(--f-offers-popular-bg); -} - -.f-card-badge { - @apply absolute top-3 right-3 bg-[--btn-background] - text-[--btn-text] text-sm font-semibold px-3 py-1 rounded-full; -} - -/* HEADER */ -.f-card-header { - @apply flex flex-col items-start gap-1; -} - -.f-card-name { - @apply text-xl font-semibold; -} - -.f-card-price { - @apply text-3xl font-extrabold text-[--f-offers-price]; -} - -/* FEATURES */ -.f-card-features { - @apply list-none p-0 m-0; -} - -.f-card-row { - display: grid; - grid-template-columns: 2fr 1fr; - gap: 0.75rem; - padding: 0.5rem 0; - border-bottom: 1px solid var(--f-offers-border); - align-items: center; -} - -.f-card-row:last-child { - border-bottom: none; -} - -.f-card-label { - @apply text-base font-medium opacity-80; -} - -.f-card-value { - @apply text-base font-semibold text-right; -} - -.f-card-value.yes { - @apply text-green-600; -} - -.f-card-value.no { - @apply text-red-600 opacity-60; -} - -/* ----------------------------- - INTELIGENTNY UKŁAD – OD MD↑ ------------------------------- */ - -@media (min-width: 768px) { - /* DOMYŚLNE: responsywnie */ + /* MOBILE: każda karta prawie pełna szerokość */ .f-card { - flex: 1 1 300px; - max-width: 360px; + /* przewijanie uwzględnia sticky navbar */ + scroll-margin-top: calc(var(--f-navbar-height, 64px) + 16px); + + flex: 1 1 100%; + max-width: 26rem; + + @apply bg-[--f-bg] text-[--f-text] border border-[--f-offers-border] rounded-2xl shadow-md p-6 relative flex flex-col gap-4; + + transition: transform 220ms ease, box-shadow 220ms ease; } - /* 4 karty → 2 + 2 */ - .f-count-4 .f-card { - flex: 0 1 calc(50% - 2rem); - max-width: 420px; + .f-card:hover { + @apply shadow-lg; + transform: translateY(-3px); } - /* 5 kart → 3 + 2 */ - .f-count-5 .f-card { - flex: 0 1 calc(33% - 2rem); - } - .f-count-5 .f-card:nth-child(n + 4) { - flex: 0 1 calc(50% - 2rem); - max-width: 420px; + /* POPULARNY PLAN */ + .f-card-popular { + border: 2px solid var(--f-offers-popular); + background: var(--f-offers-popular-bg); } - /* 7 kart → 3 + 3 + 1 (środek) */ - .f-count-7 .f-card { - flex: 0 1 calc(33% - 2rem); - } - .f-count-7 .f-card:last-child { - flex: 0 1 calc(33% - 2rem); - margin-left: auto; - margin-right: auto; + .f-card-badge { + @apply absolute top-3 right-3 bg-[--btn-background] text-[--btn-text] text-sm font-semibold px-3 py-1 rounded-full; } - /* 8 kart → 3 + 3 + 2 */ - .f-count-8 .f-card { - flex: 0 1 calc(33% - 2rem); - } - .f-count-8 .f-card:nth-child(n + 7) { - flex: 0 1 calc(50% - 2rem); - max-width: 420px; + /* HEADER */ + .f-card-header { + @apply flex flex-col items-start gap-1; } - /* 10 kart → 3 + 3 + 3 + 1 */ - .f-count-10 .f-card:last-child { - flex: 0 1 calc(33% - 2rem); - margin-left: auto; - margin-right: auto; + .f-card-name { + @apply text-xl font-semibold; } -} + .f-card-price { + @apply text-3xl font-extrabold text-[--f-offers-price]; + } + /* FEATURES */ + .f-card-features { + @apply list-none p-0 m-0; + } + .f-card-row { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 0.75rem; + padding: 0.5rem 0; + border-bottom: 1px solid var(--f-offers-border); + align-items: center; + } + .f-card-row:last-child { + border-bottom: none; + } -/* -obszar ze scrollem wewnątrz modala -.jmb-channels-scroll { - margin-top: 1rem; - padding-right: 0.25rem; - max-height: 72vh; - overflow-y: auto; -} */ + .f-card-label { + @apply text-base font-medium opacity-80; + } -/* dużo kart w wierszu */ -.jmb-channels-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); - gap: 0.9rem; -} + .f-card-value { + @apply text-base font-semibold text-right; + } -/* pojedyncza karta kanału */ -.jmb-channel-card { - background: var(--fuz-bg); - border-radius: 0.75rem; - padding: 0.75rem 0.5rem; - text-align: center; - border: 1px solid rgba(148, 163, 184, 0.25); - box-shadow: 0 1px 2px rgba(15, 23, 42, 0.15); - display: flex; - flex-direction: column; - justify-content: space-between; -} + .f-card-value.yes { + @apply text-green-600; + } -/* logo kanału */ -.jmb-channel-logo { - max-width: 90px; - max-height: 60px; - margin: 0 auto 0.5rem auto; - display: block; - object-fit: contain; -} + .f-card-value.no { + @apply text-red-600 opacity-60; + } -/* podpisy pod logo */ -.jmb-channel-name { - font-size: 0.85rem; - font-weight: 600; - margin-bottom: 0.15rem; -} + /* INTELIGENTNY UKŁAD – OD MD↑ */ + @media (min-width: 768px) { + .f-card { + flex: 1 1 300px; + max-width: 360px; + } -.jmb-channel-number { - font-size: 0.75rem; - color: #94a3b8; -} + /* 4 karty → 2 + 2 */ + .f-count-4 .f-card { + flex: 0 1 calc(50% - 2rem); + max-width: 420px; + } -/* badge "gwarantowany" */ -.jmb-channel-tag { - margin-top: 0.35rem; - font-size: 0.7rem; - display: inline-block; - padding: 0.1rem 0.5rem; - border-radius: 9999px; - background: rgba(34, 197, 94, 0.08); - color: #22c55e; -} + /* 5 kart → 3 + 2 */ + .f-count-5 .f-card { + flex: 0 1 calc(33% - 2rem); + } + .f-count-5 .f-card:nth-child(n + 4) { + flex: 0 1 calc(50% - 2rem); + max-width: 420px; + } + /* 7 kart → 3 + 3 + 1 (środek) */ + .f-count-7 .f-card { + flex: 0 1 calc(33% - 2rem); + } + .f-count-7 .f-card:last-child { + flex: 0 1 calc(33% - 2rem); + margin-left: auto; + margin-right: auto; + } + /* 8 kart → 3 + 3 + 2 */ + .f-count-8 .f-card { + flex: 0 1 calc(33% - 2rem); + } + .f-count-8 .f-card:nth-child(n + 7) { + flex: 0 1 calc(50% - 2rem); + max-width: 420px; + } + /* 10 kart → 3 + 3 + 3 + 1 */ + .f-count-10 .f-card:last-child { + flex: 0 1 calc(33% - 2rem); + margin-left: auto; + margin-right: auto; + } + } + /* ========================================= + TARGET — PODŚWIETLENIE PAKIETU PO KLIKNIĘCIU + ========================================== */ -/* === FIX: stabilny grid + flip (nie rozjeżdża kart) === */ + .f-card.is-target { + outline: none; + box-shadow: + 0 0 0 3px rgba(59, 130, 246, 0.45), + 0 10px 25px rgba(15, 23, 42, 0.18); + transform: translateY(-6px) scale(1.01); + position: relative; + background-color: var(--f-navbar-background); + z-index: 2; + } -.jmb-channels-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); - gap: 0.9rem; - align-items: stretch; /* ważne: równe wysokości w wierszu */ -} + .f-card.is-target:hover { + transform: translateY(-6px) scale(1.01); + } -.jmb-channel-card { - position: relative; - perspective: 1000px; + /* JAMBOX — GRID KANAŁÓW (MODAL) */ - /* zostawiamy Twój wygląd */ - background: var(--fuz-bg); - border-radius: 0.75rem; - border: 1px solid rgba(148, 163, 184, 0.25); - box-shadow: 0 1px 2px rgba(15, 23, 42, 0.15); + .jmb-channels-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 0.9rem; + align-items: stretch; + } - /* kluczowe: karta ma “ramę” */ - min-height: 170px; /* dopasuj: 160–200 */ - height: 100%; - padding: 0; /* padding przenosimy na face */ - overflow: hidden; /* żeby back nie wystawał */ -} + .jmb-channel-card { + position: relative; + perspective: 1000px; -.jmb-channel-inner { - position: relative; - width: 100%; - height: 100%; - transform-style: preserve-3d; - transition: transform 0.6s ease; -} + background: var(--f-bg); + color: var(--f-text); -@media (hover: hover) and (pointer: fine) { - .jmb-channel-card:hover .jmb-channel-inner { + border-radius: 0.75rem; + border: 1px solid rgba(148, 163, 184, 0.25); + box-shadow: 0 1px 2px rgba(15, 23, 42, 0.15); + + min-height: 170px; + height: 100%; + padding: 0; + overflow: hidden; + + -webkit-tap-highlight-color: transparent; + touch-action: manipulation; + cursor: pointer; + } + + .jmb-channel-inner { + position: relative; + width: 100%; + height: 100%; + transform-style: preserve-3d; + -webkit-transform-style: preserve-3d; + transition: transform 0.6s ease; + } + + /* DESKTOP: flip na hover */ + @media (hover: hover) and (pointer: fine) { + .jmb-channel-card:hover .jmb-channel-inner { + transform: rotateY(180deg); + } + } + + /* MOBILE/TAP: flip po klasie */ + .jmb-channel-card.is-flipped .jmb-channel-inner { transform: rotateY(180deg); } -} -/* front + back */ -.jmb-channel-face { - position: absolute; - inset: 0; - padding: 0.75rem 0.5rem; /* to był Twój padding z card */ - display: flex; - flex-direction: column; - justify-content: space-between; - text-align: center; + .jmb-channel-face { + position: absolute; + inset: 0; - backface-visibility: hidden; - -webkit-backface-visibility: hidden; -} + padding: 0.75rem 0.5rem; -.jmb-channel-front { - transform: rotateY(0deg); -} + display: flex; + flex-direction: column; + justify-content: space-between; + text-align: center; -.jmb-channel-back { - transform: rotateY(180deg); - text-align: left; - justify-content: flex-start; - gap: 0.5rem; -} + backface-visibility: hidden; + -webkit-backface-visibility: hidden; + } -.jmb-channel-back-title { - font-size: 0.9rem; - font-weight: 700; -} + .jmb-channel-front { + transform: rotateY(0deg); + } -.jmb-channel-desc { - font-size: 0.85rem; - line-height: 1.35; - opacity: 0.9; - overflow: auto; /* długi opis nie rozwala karty */ -} + .jmb-channel-back { + transform: rotateY(180deg); + text-align: left; + justify-content: flex-start; + gap: 0.5rem; + } -.jmb-search { - display: flex; - gap: 0.5rem; - align-items: center; - margin: 0.75rem 0 0.25rem; -} + .jmb-channel-logo { + max-width: 90px; + max-height: 60px; + margin: 0 auto 0.5rem auto; + display: block; + object-fit: contain; + } -.jmb-search-input { - flex: 1; - padding: 0.6rem 0.75rem; - border-radius: 0.75rem; - border: 1px solid rgba(148, 163, 184, 0.35); - background: var(--fuz-bg); - color: var(--fuz-text); - outline: none; -} + .jmb-channel-name { + font-size: 0.85rem; + font-weight: 600; + margin-bottom: 0.15rem; + } -.jmb-search-input:focus { - border-color: rgba(59, 130, 246, 0.55); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); -} + .jmb-channel-number { + font-size: 0.75rem; + color: rgba(148, 163, 184, 0.95); + } -.jmb-search-clear { - padding: 0.55rem 0.7rem; - border-radius: 0.75rem; - border: 1px solid rgba(148, 163, 184, 0.35); - background: transparent; -} + .jmb-channel-back-title { + font-size: 0.9rem; + font-weight: 700; + } -.jmb-search-meta { - font-size: 0.85rem; - opacity: 0.75; - margin-bottom: 0.5rem; -} + .jmb-channel-desc { + font-size: 0.85rem; + line-height: 1.35; + opacity: 0.92; + overflow: auto; -.f-card.is-target { - outline: 2px solid rgba(59, 130, 246, 0.55); - /* var(--f-link); */ - outline-offset: 4px; -} + scrollbar-width: thin; + scrollbar-color: rgba(148, 163, 184, 0.55) transparent; + } + .jmb-channel-desc::-webkit-scrollbar { + width: 10px; + } + + .jmb-channel-desc::-webkit-scrollbar-thumb { + background: rgba(148, 163, 184, 0.45); + border-radius: 9999px; + border: 3px solid transparent; + background-clip: content-box; + } + + .jmb-channel-desc::-webkit-scrollbar-track { + background: transparent; + } \ No newline at end of file