diff --git a/web/src/pages/detail/components/ArticleContent/ArticleContent.tsx b/web/src/pages/detail/components/ArticleContent/ArticleContent.tsx index 5457c887a..e644f1f83 100644 --- a/web/src/pages/detail/components/ArticleContent/ArticleContent.tsx +++ b/web/src/pages/detail/components/ArticleContent/ArticleContent.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import { memo } from 'react'; +import { memo, useRef } from 'react'; import { processContent } from './ArticleContent.utils'; import { useAutoScaleContent } from '../../hooks/useAutoScaleContent'; import { useHighlightHoverEffect } from '../../hooks/useHighlightHoverEffect'; @@ -17,26 +17,37 @@ const ArticleContent = ({ newsletterName, content, }: ArticleContentProps) => { + const containerRef = useRef(null); const bodyContent = extractBodyContent(content ?? ''); - const scale = useAutoScaleContent(ref); + const scale = useAutoScaleContent({ + layoutRef: containerRef, + contentRef: ref, + }); useHighlightHoverEffect(); return ( - + + + ); }; export default memo(ArticleContent); -const Container = styled.div<{ scale: number }>` - overflow: visible; +const Container = styled.div` + overflow: hidden; + width: 100%; +`; + +const Content = styled.div<{ scale: number }>` + width: 100%; display: flex; flex-direction: column; @@ -46,7 +57,7 @@ const Container = styled.div<{ scale: number }>` -webkit-touch-callout: default; transform: ${({ scale }) => `scale(${scale})`}; - transform-origin: top; + transform-origin: top left; user-select: text; word-break: break-all; diff --git a/web/src/pages/detail/hooks/useAutoScaleContent.ts b/web/src/pages/detail/hooks/useAutoScaleContent.ts index 6ae3c4768..0ce7d78b0 100644 --- a/web/src/pages/detail/hooks/useAutoScaleContent.ts +++ b/web/src/pages/detail/hooks/useAutoScaleContent.ts @@ -1,25 +1,45 @@ import { useEffect, useState } from 'react'; -import { PC_HORIZONTAL_PADDING } from '@/components/PageLayout/PageLayout.constants'; import type { RefObject } from 'react'; -export const useAutoScaleContent = (ref: RefObject) => { +interface UseAutoScaleContentParams { + layoutRef: RefObject; + contentRef: RefObject; +} + +export const useAutoScaleContent = ({ + layoutRef, + contentRef, +}: UseAutoScaleContentParams) => { const [scale, setScale] = useState(1); useEffect(() => { - if (!ref.current) return; + const layout = layoutRef.current; + const content = contentRef.current; + if (!layout || !content) return; + + const recompute = () => { + const layoutWidth = layout.clientWidth; + const contentWidth = content.scrollWidth; + const newScale = + contentWidth > layoutWidth ? layoutWidth / contentWidth : 1; + + setScale(newScale); - const screenWidth = window.outerWidth - PC_HORIZONTAL_PADDING; - const contentWidth = ref.current.clientWidth; + layout.style.height = + newScale === 1 ? '' : `${content.scrollHeight * newScale}px`; + }; - const newScale = - contentWidth > screenWidth ? screenWidth / contentWidth : 1; + recompute(); - if (newScale === 1) return; + const observer = new ResizeObserver(recompute); + observer.observe(content); + window.addEventListener('resize', recompute); - const newHeight = ref.current.scrollHeight * newScale; - ref.current.style.height = `${newHeight}px`; - setScale(newScale); - }, [ref]); + return () => { + observer.disconnect(); + window.removeEventListener('resize', recompute); + }; + }, [layoutRef, contentRef]); return scale; }; diff --git a/web/src/routes/_bombom/articles.$articleId.tsx b/web/src/routes/_bombom/articles.$articleId.tsx index 21a9175f1..269680cef 100644 --- a/web/src/routes/_bombom/articles.$articleId.tsx +++ b/web/src/routes/_bombom/articles.$articleId.tsx @@ -5,6 +5,7 @@ import { createFileRoute } from '@tanstack/react-router'; import { useRef } from 'react'; import { queries } from '@/apis/queries'; import MobileDetailHeader from '@/components/Header/MobileDetailHeader'; +import { MOBILE_HORIZONTAL_PADDING } from '@/components/PageLayout/PageLayout.constants'; import ProgressBar from '@/components/ProgressBar/ProgressBar'; import Spacing from '@/components/Spacing/Spacing'; import { useDevice } from '@/hooks/useDevice'; @@ -111,13 +112,15 @@ function ArticleDetailPage() { /> - + + + @@ -163,6 +166,15 @@ const ArticleContent = styled.div<{ device: Device }>` align-items: center; `; +const ArticleBodyWrapper = styled.div<{ device: Device }>` + width: ${({ device }) => + device === 'mobile' + ? `calc(100% + ${MOBILE_HORIZONTAL_PADDING}px)` + : '100%'}; + margin: ${({ device }) => + device === 'mobile' ? `0 -${MOBILE_HORIZONTAL_PADDING / 2}px` : '0'}; +`; + const ArticleProgressBar = styled(ProgressBar)<{ device: Device }>` position: fixed; top: ${({ device, theme }) =>