mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
## I have read the CONTRIBUTING.md file. YES ## What kind of change does this PR introduce? This PR fixes a mobile layout bug on blog posts where long unwrapped URLs made the article column wider than its flex parent. With `justify-center`, that overflow centered the column and clipped content on both sides. It also hardens the reading progress bar so it no longer uses `100vw`, matching the overflow-safe pattern already used on changelog prose. ## What is the current behavior? - On mobile Safari, `/blog/are-supabase-docs-agent-friendly` shifts left with empty space on the right and clipped title/body text - A raw long URL in a blockquote (`row-level-security.md`) expands the flex column past the parent width - The reading progress fill uses `w-screen` (`100vw`) with a negative `translate3d`, which can widen layout outside the blog `overflow-x-clip` shell ## What is the new behavior? - Blog main column uses `min-w-0 w-full` so flex children cannot outgrow the parent - Blog prose uses `wrap-break-word` (same as changelog) so long URLs wrap - Scroll progress bar uses parent width plus `overflow-hidden` instead of `w-screen` ## Additional context - Branch: `fix-docs-agents-blog-post-on-mobile` - Files: `apps/www/components/Blog/BlogPostRenderer.tsx`, `apps/www/components/ScrollProgress.tsx` - Verification: | Check | Result | | --- | --- | | Production at 390px: title `h1` left ≈ -42 (shifted) | pass (reproduced) | | Preview at 390px: title `h1` left = 24, right = 366 | pass | | `scrollWidth === clientWidth` on preview | pass | | Progress bar still fills on scroll | pass | | Hero image still `hidden lg:block` (unchanged) | pass | ### Proof: mobile blog no longer shifts left **Verified:** production before vs PR www preview after, both captured at CSS viewport 390×844 via `page.setViewport` (not Chrome `--window-size`) | [Before (production)](https://supabase.com/blog/are-supabase-docs-agent-friendly) | [After (PR preview)](https://zone-www-dot-com-git-fix-docs-agents-blog-post-4e52df-supabase.vercel.app/blog/are-supabase-docs-agent-friendly) | | --- | --- | |  |  | - **Before:** https://supabase.com/blog/are-supabase-docs-agent-friendly - **After:** https://zone-www-dot-com-git-fix-docs-agents-blog-post-4e52df-supabase.vercel.app/blog/are-supabase-docs-agent-friendly ### Test plan - [ ] Open [production](https://supabase.com/blog/are-supabase-docs-agent-friendly) at ~390px and confirm the clipped/shifted layout - [ ] Open the [PR www preview](https://zone-www-dot-com-git-fix-docs-agents-blog-post-4e52df-supabase.vercel.app/blog/are-supabase-docs-agent-friendly) at ~390px - [ ] Confirm title, authors, and body are fully visible with no empty strip on the right - [ ] Confirm `document.documentElement.scrollWidth === document.documentElement.clientWidth` - [ ] Scroll and confirm the green reading progress bar still fills - [ ] Spot-check another blog post without a raw long URL for no layout regression Co-authored-by: Nik Richers <nik@validmind.ai>
50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
'use client'
|
|
|
|
import { usePathname } from 'next/navigation'
|
|
import React, { useEffect, useState } from 'react'
|
|
|
|
const ScrollProgress = () => {
|
|
const [progressPercentage, setProgressPercentage] = useState(0)
|
|
const pathname = usePathname()
|
|
|
|
const isBlogPost = /^\/blog\/[^/]+\/?$/.test(pathname ?? '')
|
|
|
|
const handleScroll = () => {
|
|
if (typeof document === 'undefined') return null
|
|
const article = document?.querySelector('article')
|
|
if (!article) return null
|
|
const { top, height } = (article as any)?.getBoundingClientRect()
|
|
let scrollDistance = -top
|
|
let progressPercentage =
|
|
(scrollDistance / (height - document.documentElement.clientHeight)) * 100
|
|
setProgressPercentage(progressPercentage)
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (!isBlogPost) return
|
|
window.addEventListener('scroll', handleScroll)
|
|
return () => {
|
|
window.removeEventListener('scroll', handleScroll)
|
|
}
|
|
}, [isBlogPost])
|
|
|
|
if (!isBlogPost) return null
|
|
|
|
let isActive = progressPercentage <= 100
|
|
|
|
return (
|
|
<div className="relative h-[2px] w-full overflow-hidden">
|
|
<div
|
|
className="absolute inset-y-0 left-0 right-0 h-full bg-brand will-change-transform transition-opacity"
|
|
style={{
|
|
display: isActive ? 'absolute' : 'relative',
|
|
transform: `translate3d(${isActive ? progressPercentage - 100 + '%' : '0'},0,0)`,
|
|
opacity: isActive ? 1 : 0,
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default ScrollProgress
|