@@ -116,6 +84,7 @@ let currentAddedIngredients = [];
let currentProductSelections = {};
let expandedAlternatives = new Set();
let ingredientCard = null;
+let resetScrollState = null;
function isPlannedMode() {
return currentMode === 'planned';
@@ -225,31 +194,11 @@ function populateDetail(recipeId, options = {}) {
heroLabel.textContent = `Zdjęcie: ${recipe.title}`;
}
document.getElementById('rd-title').textContent = recipe.title;
- document.getElementById('rd-time').textContent = `${recipe.minutes} min`;
document.getElementById('rd-add-to-planner-btn')?.classList.toggle('hidden', isPlannedMode());
- const tagsHtml = [];
- for (const slotId of recipe.allowedSlots) {
- const label = slotLabelMap[slotId];
- if (label) tagsHtml.push(renderTagChip(label));
- }
- for (const tag of (recipe.tags || [])) {
- tagsHtml.push(renderTagChip(tag));
- }
- document.getElementById('rd-tags').innerHTML = tagsHtml.join('');
-
renderIngredients(recipe);
renderSteps(recipe);
-
- const tabBtns = document.querySelectorAll('.rd-tab-btn');
- const tabs = document.querySelectorAll('.rd-tab-content');
- tabBtns.forEach((b) => {
- setTabButtonState(b, false);
- });
- setTabButtonState(tabBtns[0], true);
- tabs.forEach((t) => { t.classList.add('hidden'); t.classList.remove('block'); });
- document.getElementById('rd-tab-ingredients')?.classList.remove('hidden');
- document.getElementById('rd-tab-ingredients')?.classList.add('block');
+ resetScrollState?.();
}
/* ── helpers ───────────────────────────────────────────── */
@@ -523,9 +472,9 @@ function renderSteps(recipe) {
container.innerHTML = `
${steps.map((step, i) => `
-
-
${i + 1}
-
+
+
${i + 1}.
+
${escapeHtml(step)}
`).join('')}
`;
}
@@ -536,37 +485,81 @@ export function setupRecipeDetail() {
ingredientCard = createIngredientCardController({ idBase: 'rd-ing-card', defaultSourceNote: 'Z planera' });
ingredientCard.bind();
- document.querySelectorAll('.rd-tab-btn').forEach((btn) => {
- btn.addEventListener('click', () => {
- const tabId = btn.dataset.rdTab;
- document.querySelectorAll('.rd-tab-content').forEach((el) => {
- el.classList.add('hidden');
- el.classList.remove('block');
- });
- const target = document.getElementById(`rd-tab-${tabId}`);
- if (target) {
- target.classList.remove('hidden');
- target.classList.add('block');
- target.parentElement.scrollTop = 0;
- }
+ /* ── collapsing hero on scroll ─────────────── */
- document.querySelectorAll('.rd-tab-btn').forEach((b) => {
- setTabButtonState(b, false);
- });
- setTabButtonState(btn, true);
- });
- });
+ const HERO_MAX = 236;
+ const scrollContainer = document.getElementById('rd-scroll-container');
+ const hero = document.getElementById('rd-hero');
+ const heroImg = document.getElementById('rd-hero-img');
+ const topActionButtons = [
+ document.getElementById('rd-back-btn'),
+ document.getElementById('rd-add-to-planner-btn'),
+ ].filter(Boolean);
- /* ── tab-bar scroll shadow ─────────────────── */
-
- const scrollContainer = document.querySelector('#recipe-detail-view .overflow-y-auto');
- const tabBar = document.getElementById('rd-tab-bar');
- if (scrollContainer && tabBar) {
- scrollContainer.addEventListener('scroll', () => {
- tabBar.classList.toggle('rd-scrolled', scrollContainer.scrollTop > 2);
+ function syncTopActionButtons(progress) {
+ const shadowY = 3 + (progress * 3);
+ const shadowBlur = 8 + (progress * 6);
+ const shadowAlpha = 0.28 + (progress * 0.16);
+ const backgroundAlpha = 0.93 + (progress * 0.05);
+ topActionButtons.forEach((button) => {
+ const isRoundButton = button.id === 'rd-back-btn';
+ const effectiveShadowY = isRoundButton ? shadowY + 1 : shadowY;
+ const effectiveShadowBlur = isRoundButton ? shadowBlur + 1 : shadowBlur;
+ const effectiveShadowAlpha = isRoundButton ? shadowAlpha + 0.05 : shadowAlpha;
+ button.style.boxShadow = `0 ${effectiveShadowY}px ${effectiveShadowBlur}px rgba(0,0,0,${effectiveShadowAlpha})`;
+ button.style.background = `rgba(57,57,55,${backgroundAlpha})`;
});
}
+ if (scrollContainer && hero) {
+ let ticking = false;
+ let lastTouchY = null;
+ scrollContainer.addEventListener('scroll', () => {
+ if (ticking) return;
+ ticking = true;
+ requestAnimationFrame(() => {
+ const scrollY = Math.max(0, scrollContainer.scrollTop);
+ const collapse = Math.min(scrollY, HERO_MAX);
+ const progress = collapse / HERO_MAX;
+ hero.style.height = `${HERO_MAX - collapse}px`;
+ hero.style.opacity = String(Math.max(0, 1 - collapse / HERO_MAX));
+ syncTopActionButtons(progress);
+ if (heroImg) {
+ heroImg.style.transform = `translateY(${collapse * 0.4}px) scale(${1 + collapse * 0.001})`;
+ }
+ ticking = false;
+ });
+ });
+
+ scrollContainer.addEventListener('touchstart', (e) => {
+ lastTouchY = e.touches[0]?.clientY ?? null;
+ }, { passive: true });
+
+ scrollContainer.addEventListener('touchmove', (e) => {
+ const touchY = e.touches[0]?.clientY;
+ if (touchY == null) return;
+ if (scrollContainer.scrollTop <= 0 && lastTouchY != null && touchY > lastTouchY) {
+ e.preventDefault();
+ }
+ lastTouchY = touchY;
+ }, { passive: false });
+
+ scrollContainer.addEventListener('touchend', () => {
+ lastTouchY = null;
+ }, { passive: true });
+
+ scrollContainer.addEventListener('touchcancel', () => {
+ lastTouchY = null;
+ }, { passive: true });
+ }
+
+ resetScrollState = () => {
+ if (scrollContainer) scrollContainer.scrollTop = 0;
+ if (hero) { hero.style.height = `${HERO_MAX}px`; hero.style.opacity = '1'; }
+ syncTopActionButtons(0);
+ if (heroImg) heroImg.style.transform = '';
+ };
+
/* ── planner — delegate to MealPlanEditor ─────── */
document.getElementById('rd-add-to-planner-btn')?.addEventListener('click', () => {