Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions web/src/pages/detail/components/ArticleContent/ArticleContent.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -17,26 +17,37 @@ const ArticleContent = ({
newsletterName,
content,
}: ArticleContentProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const bodyContent = extractBodyContent(content ?? '');
const scale = useAutoScaleContent(ref);
const scale = useAutoScaleContent({
layoutRef: containerRef,
contentRef: ref,
});

useHighlightHoverEffect();

return (
<Container
ref={ref}
scale={scale}
dangerouslySetInnerHTML={{
__html: processContent(newsletterName, bodyContent),
}}
/>
<Container ref={containerRef}>
<Content
ref={ref}
scale={scale}
dangerouslySetInnerHTML={{
__html: processContent(newsletterName, bodyContent),
}}
/>
</Container>
);
};

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;
Expand All @@ -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;
Expand Down
44 changes: 32 additions & 12 deletions web/src/pages/detail/hooks/useAutoScaleContent.ts
Original file line number Diff line number Diff line change
@@ -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<HTMLDivElement | null>) => {
interface UseAutoScaleContentParams {
layoutRef: RefObject<HTMLDivElement | null>;
contentRef: RefObject<HTMLDivElement | null>;
}

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;
};
26 changes: 19 additions & 7 deletions web/src/routes/_bombom/articles.$articleId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -111,13 +112,15 @@ function ArticleDetailPage() {
/>
<Divider />

<ArticleBody
contentRef={contentRef}
articleId={articleIdNumber}
articleTitle={currentArticle.title}
newsletterName={currentArticle.newsletter.name}
articleContent={currentArticle.contents}
/>
<ArticleBodyWrapper device={device}>
<ArticleBody
contentRef={contentRef}
articleId={articleIdNumber}
articleTitle={currentArticle.title}
newsletterName={currentArticle.newsletter.name}
articleContent={currentArticle.contents}
/>
</ArticleBodyWrapper>
<Spacing size={24} />
<Divider />

Expand Down Expand Up @@ -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 }) =>
Expand Down
Loading