Skip to content

Commit da7dd7d

Browse files
committed
fix: ad condition
1 parent 7e3de4f commit da7dd7d

File tree

9 files changed

+286
-63
lines changed

9 files changed

+286
-63
lines changed

src/components/common/MarkdownRender.tsx

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface MarkdownRenderProps {
2828
codeTheme?: string;
2929
onConvertFinish?: (html: string) => any;
3030
editing?: boolean;
31+
shouldShowAds?: boolean;
3132
}
3233

3334
function sanitizeEventScript(htmlString: string) {
@@ -208,6 +209,7 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
208209
codeTheme = 'atom-one',
209210
onConvertFinish,
210211
editing,
212+
shouldShowAds = false,
211213
}) => {
212214
const [html, setHtml] = useState(
213215
ssrEnabled
@@ -232,6 +234,8 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
232234
const [element, setElement] = useState<RenderedElement>(null);
233235
const [hasTagError, setHasTagError] = useState(false);
234236
const [delay, setDelay] = useState(25);
237+
const [hasEnoughBlock, setHasEnoughBlock] = useState(false);
238+
const [htmlWithAds, setHtmlWithAds] = useState('');
235239

236240
const throttledUpdate = React.useMemo(() => {
237241
return throttle(delay, (markdown: string) => {
@@ -288,6 +292,76 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
288292
throttledUpdate(markdown);
289293
}, [markdown, throttledUpdate]);
290294

295+
useEffect(() => {
296+
if (!shouldShowAds || !html) {
297+
setHtmlWithAds('');
298+
return;
299+
}
300+
301+
const parser = new DOMParser();
302+
const doc = parser.parseFromString(html, 'text/html');
303+
const blockElements = doc.querySelectorAll('p, h1, h2, h3, h4, h5, h6, blockquote, pre, ul, ol, hr, table');
304+
305+
console.log('Total blocks:', blockElements.length);
306+
307+
const hasEnough = blockElements.length >= 20;
308+
setHasEnoughBlock(hasEnough);
309+
console.log('hasEnoughBlock:', hasEnough);
310+
311+
if (hasEnough) {
312+
// Find the position to insert ad
313+
let targetBlock = null;
314+
let insertPosition = 19; // 20th block (0-based index)
315+
316+
// Look for first h1, h2, h3 after 20th block
317+
for (let i = 20; i < blockElements.length && i < 50; i++) {
318+
const block = blockElements[i];
319+
if (block.tagName === 'H1' || block.tagName === 'H2' || block.tagName === 'H3') {
320+
targetBlock = block;
321+
insertPosition = i;
322+
break;
323+
}
324+
}
325+
326+
// If heading found and before index 50, insert before it
327+
// Otherwise insert after 20th block
328+
const blockToInsertAfter = targetBlock
329+
? blockElements[insertPosition - 1]
330+
: blockElements[19];
331+
332+
if (blockToInsertAfter) {
333+
const adDiv = doc.createElement('ins');
334+
adDiv.className = 'adsbygoogle';
335+
adDiv.style.display = 'block';
336+
adDiv.style.textAlign = 'center';
337+
adDiv.setAttribute('data-ad-layout', 'in-article');
338+
adDiv.setAttribute('data-ad-format', 'fluid');
339+
adDiv.setAttribute('data-ad-client', 'ca-pub-5574866530496701');
340+
adDiv.setAttribute('data-ad-slot', '9632367492');
341+
342+
// Insert after the target block (or before heading if found)
343+
if (targetBlock) {
344+
targetBlock.parentNode?.insertBefore(adDiv, targetBlock);
345+
} else {
346+
blockToInsertAfter.parentNode?.insertBefore(adDiv, blockToInsertAfter.nextSibling);
347+
}
348+
349+
// Set the modified HTML
350+
const updatedHtml = doc.body.innerHTML;
351+
setHtmlWithAds(updatedHtml);
352+
353+
// Push ad after 1 second
354+
setTimeout(() => {
355+
(window.adsbygoogle = window.adsbygoogle || []).push({});
356+
}, 1000);
357+
} else {
358+
setHtmlWithAds('');
359+
}
360+
} else {
361+
setHtmlWithAds('');
362+
}
363+
}, [html, shouldShowAds]);
364+
291365
return (
292366
<Typography>
293367
<Helmet>
@@ -312,7 +386,7 @@ const MarkdownRender: React.FC<MarkdownRenderProps> = ({
312386
) : (
313387
<MarkdownRenderBlock
314388
className={codeTheme}
315-
dangerouslySetInnerHTML={{ __html: html }}
389+
dangerouslySetInnerHTML={{ __html: htmlWithAds || html }}
316390
/>
317391
)}
318392
</Typography>

src/components/common/PostCardGrid.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ const Block = styled.div`
8888
display: flex;
8989
margin: -1rem;
9090
flex-wrap: wrap;
91+
justify-content: center;
9192
${mediaQuery(767)} {
9293
margin: 0;
9394
}

src/components/post/PostContent.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const PostContentBlock = styled.div`
2222
export interface PostContentProps {
2323
isMarkdown: boolean;
2424
body: string;
25+
shouldShowAds?: boolean;
2526
}
2627

2728
function optimizeImagesFromPost(markdown: string) {
@@ -45,7 +46,7 @@ function optimizeImagesFromPost(markdown: string) {
4546
}, markdown);
4647
}
4748

48-
const PostContent: React.FC<PostContentProps> = ({ isMarkdown, body }) => {
49+
const PostContent: React.FC<PostContentProps> = ({ isMarkdown, body, shouldShowAds = false }) => {
4950
const [html, setHtml] = useState(isMarkdown ? null : body);
5051
const dispatch = usePostViewerDispatch();
5152
const imageOptimizedPost = useMemo(
@@ -65,6 +66,7 @@ const PostContent: React.FC<PostContentProps> = ({ isMarkdown, body }) => {
6566
<MarkdownRender
6667
markdown={imageOptimizedPost}
6768
onConvertFinish={setHtml}
69+
shouldShowAds={shouldShowAds}
6870
/>
6971
) : (
7072
<PostHtmlContent html={body} />

src/components/post/PostHead.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export interface PostHeadProps {
147147
isPrivate?: boolean;
148148
mobileLikeButton: React.ReactNode;
149149
followButton: React.ReactNode;
150+
sideAd?: React.ReactNode;
150151
onOpenStats(): void;
151152
}
152153

@@ -169,6 +170,7 @@ const PostHead: React.FC<PostHeadProps> = ({
169170
mobileLikeButton,
170171
onOpenStats,
171172
followButton,
173+
sideAd,
172174
}) => {
173175
const [askRemove, toggleAskRemove] = useToggle(false);
174176

@@ -211,6 +213,7 @@ const PostHead: React.FC<PostHeadProps> = ({
211213
</SubInfo>
212214
<TagList tags={tags} link />
213215
{shareButtons}
216+
{sideAd}
214217
{toc}
215218
{series && (
216219
<PostSeriesInfo

src/components/post/SideAd.tsx

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import React, { useEffect, useState, useRef, useCallback } from 'react';
2+
import styled from 'styled-components';
3+
import media from '../../lib/styles/media';
4+
import { getScrollTop } from '../../lib/utils';
5+
6+
const Wrapper = styled.div`
7+
position: relative;
8+
margin-top: 2rem;
9+
${media.large} {
10+
display: none;
11+
}
12+
`;
13+
14+
const Positioner = styled.div`
15+
position: absolute;
16+
top: 182px;
17+
`;
18+
19+
const AdBlock = styled.div<{ width: number; height: number }>`
20+
width: ${(props) => props.width}px;
21+
height: ${(props) => props.height}px;
22+
// background: #e0e0e0;
23+
// border-radius: 4px;
24+
display: flex;
25+
align-items: center;
26+
justify-content: center;
27+
// color: #666;
28+
// font-size: 14px;
29+
`;
30+
31+
function AdInsComponent() {
32+
useEffect(() => {
33+
(window.adsbygoogle = window.adsbygoogle || []).push({});
34+
}, []);
35+
36+
return (
37+
<ins
38+
className="adsbygoogle"
39+
style={{
40+
display: 'inline-block',
41+
width: '160px',
42+
height: '600px',
43+
}}
44+
data-ad-client="ca-pub-5574866530496701"
45+
data-ad-slot="1933254146"
46+
></ins>
47+
);
48+
}
49+
50+
export default function SideAd() {
51+
const [isDesktop, setIsDesktop] = useState(false);
52+
const [fixed, setFixed] = useState(false);
53+
const [y, setY] = useState(0);
54+
const element = useRef<HTMLDivElement | null>(null);
55+
56+
const setup = useCallback(() => {
57+
if (!element.current) return;
58+
const pos = element.current.getBoundingClientRect();
59+
setY(pos.top + getScrollTop());
60+
}, []);
61+
62+
const onScroll = useCallback(() => {
63+
const scrollTop = getScrollTop();
64+
const nextFixed = scrollTop + 112 + 182 > y;
65+
if (fixed !== nextFixed) {
66+
setFixed(nextFixed);
67+
}
68+
}, [fixed, y]);
69+
70+
useEffect(() => {
71+
const userAgent = navigator.userAgent.toLowerCase();
72+
const isMobile =
73+
/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(
74+
userAgent,
75+
);
76+
const hasMinWidth = window.innerWidth >= 1200;
77+
78+
setIsDesktop(!isMobile && hasMinWidth);
79+
}, []);
80+
81+
useEffect(() => {
82+
setup();
83+
}, [setup]);
84+
85+
useEffect(() => {
86+
window.addEventListener('scroll', onScroll);
87+
return () => {
88+
window.removeEventListener('scroll', onScroll);
89+
};
90+
}, [onScroll]);
91+
92+
const size = { width: 160, height: 600 };
93+
const leftPosition = '-208px';
94+
95+
return (
96+
<Wrapper>
97+
<Positioner ref={element} style={{ left: leftPosition }}>
98+
{isDesktop ? (
99+
<AdBlock
100+
width={size.width}
101+
height={size.height}
102+
style={{
103+
position: fixed ? 'fixed' : undefined,
104+
top: fixed ? 282 : undefined,
105+
}}
106+
>
107+
<AdInsComponent />
108+
</AdBlock>
109+
) : null}
110+
</Positioner>
111+
</Wrapper>
112+
);
113+
}

src/components/velog/VelogPageTemplate.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { createContext, useContext, useState } from 'react';
22
import styled from 'styled-components';
33
import { useTheme } from '../../lib/hooks/useTheme';
4-
import { themedPalette } from '../../lib/styles/themes';
54
import PageTemplate from '../base/PageTemplate';
65

76
const VelogPageTemplateBlock = styled(PageTemplate)`
@@ -28,10 +27,7 @@ export function useSetShowFooter() {
2827

2928
function GraphCDNFooter() {
3029
const theme = useTheme();
31-
const img =
32-
theme === 'dark'
33-
? 'https://graphcdn.io/badge-light.svg'
34-
: 'https://graphcdn.io/badge.svg';
30+
const img = 'https://i.imgur.com/BMhDSUt.png';
3531
return (
3632
<Block>
3733
<a href="https://graphcdn.io/?ref=powered-by">
@@ -42,7 +38,7 @@ function GraphCDNFooter() {
4238
}
4339

4440
const Block = styled.div`
45-
background: ${themedPalette.bg_page1};
41+
background: transparent;
4642
display: flex;
4743
justify-content: center;
4844
padding-top: 1rem;

0 commit comments

Comments
 (0)