Skip to content

Commit

Permalink
feat: 지난 아티클 50% 검열 ui 추가 (#ATR-614)
Browse files Browse the repository at this point in the history
  • Loading branch information
LC-02s committed Oct 15, 2024
1 parent c1cec3a commit 7dd757b
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 33 deletions.
Binary file added apps/service/public/images/service-banner.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export default async function PrevArticleDetailPage({
title={data.title}
contentUrl={data.contentUrl}
newsletterId={data.newsletter.id}
newsletterUrl={
data.newsletter.prevArticleListUrl ?? data.newsletter.homepageUrl
}
newsletterThumbnailUrl={data.newsletter.thumbnailUrl}
newsletterName={data.newsletter.name}
receivedAt={data.receivedAt}
Expand Down
2 changes: 2 additions & 0 deletions apps/service/src/entities/auth/ui/ProfileDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useAuth } from '../model'
function ServerIcon({ className }: { className?: string }) {
return (
<svg
// TODO: 아이콘 추가 시 제거
xmlns="http://www.w3.org/2000/svg"
className={className}
width="1em"
Expand All @@ -39,6 +40,7 @@ function ServerIcon({ className }: { className?: string }) {
function NewTabIcon({ className }: { className?: string }) {
return (
<svg
// TODO: 아이콘 추가 시 제거
xmlns="http://www.w3.org/2000/svg"
className={className}
width="1em"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const DEFAULT_CENSORED_ARTICLE_HEIGHT = 1200

export default DEFAULT_CENSORED_ARTICLE_HEIGHT
1 change: 1 addition & 0 deletions apps/service/src/entities/user-article/constant/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as DEFAULT_LIST_SIZE } from './defaultListSize'
export * from './sortButton'
export { default as DEFAULT_CENSORED_ARTICLE_HEIGHT } from './defaultCensoredArticleHeight'
1 change: 1 addition & 0 deletions apps/service/src/entities/user-article/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './util'
14 changes: 14 additions & 0 deletions apps/service/src/entities/user-article/lib/util/getFrameHeight.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { DEFAULT_CENSORED_ARTICLE_HEIGHT } from '../../constant'

export default function getFrameHeight({
height,
isPrevArticle,
}: {
height: number
isPrevArticle: boolean
}) {
if (isPrevArticle) {
return `${height / 2 > DEFAULT_CENSORED_ARTICLE_HEIGHT ? DEFAULT_CENSORED_ARTICLE_HEIGHT : height / 2}px`
}
return `${height}px`
}
1 change: 1 addition & 0 deletions apps/service/src/entities/user-article/lib/util/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as getFrameHeight } from './getFrameHeight'
109 changes: 76 additions & 33 deletions apps/service/src/entities/user-article/ui/ArticleView.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
'use client'

import Link from 'next/link'
import { useEffect, useRef, useState } from 'react'
import { Badge } from '@attraction/design-system/dist'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Badge } from '@attraction/ds-core'
import { getTimeFromNow, twcn } from '@attraction/utils'
import { useWindowEvent } from '@attraction/ds-hooks'
import { ErrorGuideTxt, ThumbnailImage } from '@/shared/ui'
import { censoringAnchorTags } from '@/shared/lib'
import { getTimeFromNow } from '@attraction/utils'
import { getFrameHeight } from '../lib'
import BookmarkBtn from './BookmarkBtn'
import OfflineDownloadBtn from './OfflineDownloadBtn'

function NewTabIcon({ className }: { className?: string }) {
return (
<svg
// TODO: 아이콘 추가 시 제거
xmlns="http://www.w3.org/2000/svg"
className={className}
width="1em"
height="1em"
viewBox="0 0 24 24">
<path
fill="currentColor"
d="M12 1.25h-.057c-2.309 0-4.118 0-5.53.19c-1.444.194-2.584.6-3.479 1.494c-.895.895-1.3 2.035-1.494 3.48c-.19 1.411-.19 3.22-.19 5.529v.114c0 2.309 0 4.118.19 5.53c.194 1.444.6 2.584 1.494 3.479c.895.895 2.035 1.3 3.48 1.494c1.411.19 3.22.19 5.529.19h.114c2.309 0 4.118 0 5.53-.19c1.444-.194 2.584-.6 3.479-1.494c.895-.895 1.3-2.035 1.494-3.48c.19-1.411.19-3.22.19-5.529V12a.75.75 0 0 0-1.5 0c0 2.378-.002 4.086-.176 5.386c-.172 1.279-.5 2.05-1.069 2.62c-.57.569-1.34.896-2.619 1.068c-1.3.174-3.008.176-5.386.176s-4.086-.002-5.386-.176c-1.279-.172-2.05-.5-2.62-1.069c-.569-.57-.896-1.34-1.068-2.619c-.174-1.3-.176-3.008-.176-5.386s.002-4.086.176-5.386c.172-1.279.5-2.05 1.069-2.62c.57-.569 1.34-.896 2.619-1.068c1.3-.174 3.008-.176 5.386-.176a.75.75 0 0 0 0-1.5"
/>
<path
fill="currentColor"
d="M12.47 10.47a.75.75 0 1 0 1.06 1.06l7.72-7.72v3.534a.75.75 0 0 0 1.5 0V2a.75.75 0 0 0-.75-.75h-5.344a.75.75 0 0 0 0 1.5h3.533z"
/>
</svg>
)
}

interface ArticleViewProps {
id: number
title: string
contentUrl: string
newsletterId: string | number
newsletterUrl?: string | null
newsletterThumbnailUrl: string
newsletterName: string
receivedAt: string
Expand All @@ -36,7 +60,7 @@ export default function ArticleView({
useEffect(() => setLoad?.(isIframeLoad), [setLoad, isIframeLoad])

const iframeRef = useRef<HTMLIFrameElement | null>(null)
const iframeLoadHandler = () => {
const iframeLoadHandler = useCallback(() => {
try {
const iframe = iframeRef.current
if (iframe === null) return
Expand All @@ -50,32 +74,33 @@ export default function ArticleView({
}

iframe.style.display = 'block'
iframe.style.height = `${iframeDoc.body.scrollHeight}px`
iframe.style.height = getFrameHeight({
height: iframeDoc.body.scrollHeight,
isPrevArticle: articleType === 'prev',
})

window.scrollTo(0, 0)
if (articleType === 'user') window.scrollTo(0, 0)
censoringAnchorTags(iframeDoc)
setIframeLoad(true)
} catch {
setIframeError(true)
}
}
}, [articleType])

useEffect(() => {
const iframeResizeHandler = useCallback(() => {
const iframe = iframeRef.current
const iframeResizeHandler = () => {
if (iframe === null) return
if (iframe === null) return

const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document
if (!iframeDoc) return
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document
if (!iframeDoc) return

iframe.style.height = `${iframeDoc.body.scrollHeight}px`
}
iframe.style.height = getFrameHeight({
height: iframeDoc.body.scrollHeight,
isPrevArticle: articleType === 'prev',
})
}, [articleType])

window.addEventListener('resize', iframeResizeHandler)
return () => {
window.removeEventListener('resize', iframeResizeHandler)
}
}, [])
useWindowEvent('resize', iframeResizeHandler)

return (
<div className="h-auto min-h-dvh w-full pt-8 md:px-5 md:pb-12 md:pt-5">
Expand All @@ -102,7 +127,7 @@ export default function ArticleView({
</Link>
<p className="flex items-center gap-2 text-gray-500 dark:text-gray-400">
<span>{getTimeFromNow(data.receivedAt)}</span>
<Badge variant="blue">
<Badge color="blue">
{data.readingTime ? `약 ${data.readingTime}분` : '1분 미만'}
</Badge>
</p>
Expand All @@ -115,11 +140,20 @@ export default function ArticleView({
)}
</div>
</div>
<div className="min-h-full w-full overflow-hidden md:rounded-lg">
{!isIframeError &&
!!data.contentUrl &&
/.html$/g.test(data.contentUrl) ? (
<>
<div
className={twcn(
'relative',
articleType === 'prev' &&
isIframeLoad &&
'mb-32 after:absolute after:inset-x-0 after:bottom-0 after:z-10 after:h-40 after:bg-gradient-to-t after:from-gray-50 after:to-transparent md:mb-12 md:after:from-white dark:after:from-gray-900 md:dark:after:from-gray-800',
)}>
<div className="min-h-full w-full overflow-hidden md:rounded-lg">
{!isIframeLoad && (
<div className="min-h-dvh bg-gray-100 md:rounded-lg dark:bg-gray-600" />
)}
{!isIframeError &&
!!data.contentUrl &&
/.html$/g.test(data.contentUrl) ? (
<iframe
ref={(node) => {
iframeRef.current = node
Expand All @@ -130,14 +164,23 @@ export default function ArticleView({
onLoad={iframeLoadHandler}
onError={() => setIframeError(true)}
/>
{!isIframeLoad && (
<div className="min-h-dvh bg-gray-100 md:rounded-lg dark:bg-gray-600" />
)}
</>
) : (
<div className="px-5">
<ErrorGuideTxt />
</div>
) : (
<div className="px-5">
<ErrorGuideTxt />
</div>
)}
</div>
{articleType === 'prev' && isIframeLoad && (
<p className="absolute inset-x-0 bottom-0 z-20 inline-flex translate-y-1/2 items-center justify-center">
<Link
href={data.newsletterUrl ?? `/newsletter/${data.newsletterId}`}
target={!data.newsletterUrl ? '_self' : '_blank'}
title={`뉴스레터 홈페이지 바로가기: ${data.newsletterName}`}
className="flex items-center justify-center gap-3 rounded-full border border-blue-100 bg-blue-50 px-6 py-3 text-blue-400 transition-colors hover:bg-blue-100 dark:border-blue-700 dark:bg-gray-800 dark:text-blue-300 dark:hover:bg-blue-800">
<span>지난아티클들 읽어 보기</span>
<NewTabIcon className="text-lg" />
</Link>
</p>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ interface GetPrevArticleResponse {
name: string
category: string
thumbnailUrl: string
homepageUrl: string
prevArticleListUrl: string | null
}
}
}
Expand Down

0 comments on commit 7dd757b

Please sign in to comment.