{"id":12057,"date":"2026-10-12T08:49:17","date_gmt":"2026-10-11T23:49:17","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=12057"},"modified":"2026-10-12T13:31:02","modified_gmt":"2026-10-12T04:31:02","slug":"nextjs-sns-server-51-2","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/10\/12\/nextjs-sns-server-51-2\/","title":{"rendered":"[nextjs]SNS Server-51(myapp61+)[Active theme]\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc5ec\uae30\uc11c\ub294 \uc561\ud2f0\ube0c\ud14c\ub9c8\uc640 \ud0c0\uc784\ub77c\uc778\uc758 \ucee4\uc11c \ud398\uc774\uc9c0 \ub124\uc774\uc158 \uad6c\uc870\ub97c \ubd84\uc11d\ud574 \ubd05\ub2c8\ub2e4.<br>Here, we analyze the cursor-based pagination structure of Active Themes and Timelines.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ucee4\uc11c\ud398\uc774\uc9c0\ub124\uc774\uc158\uc740(\ud398\uc774\uc9c0 \ub124\uc774\uc158  + \ubb34\ud55c\uc2a4\ud06c\ub864)\uc785\ub2c8\ub2e4.<br>Cursor-based pagination is a combination of pagination and infinite scrolling.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \ubcf4\ud1b5 \uc6b0\ub9ac\uac00 \ubaa8\ubc14\uc77c \ud3f0\uc5d0\uc11c \uc2a4\ud06c\ub864\uc744 \uc544\ub798\ub85c \ub0b4\ub824\uc11c \ud654\uba74\ub05d\uc5d0 \ub3c4\ub2ec\ud558\uba74 \ub370\uc774\ud130\ub97c \ucd94\uac00\ub85c \ub4a4\uc5d0 \ubd99\uc774\ub294 \ubc29\uc2dd\uc744 \uc758\ubbf8\ud569\ub2c8\ub2e4.<br>It typically refers to the method where additional data is appended as you scroll down on a mobile phone and reach the bottom of the screen.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc774 \ubd80\ubd84\uc744 \uc774 SNS\ud398\uc774\uc9c0\uc5d0\uc11c \uad6c\ud604\ud558\ub294\uac8c \ucee4\uc11c \ud398\uc774\uc9c0 \ub124\uc774\uc158\uc785\ub2c8\ub2e4.<br>The key feature being implemented on this social media page is pagination.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udcc1 \ud14c\ub9c8\ud638\ucd9c \ubc0f \ud0c0\uc784\ub77c\uc778 \ub9ac\uc2a4\ud2b8\ud638\ucd9c \ud750\ub984<br>Flow of Theme and Timeline List Retrieval<\/p>\n\n\n\n<p>\u2714\ufe0f \ud398\uc774\uc9c0\ub124\uc774\uc158\uc774 \uc801\uc6a9\ub418\ub294 \ubd80\ubd84\uc740 \ud14c\ub9c8\ub514\ub809\ud1a0\ub9ac\uc758 TimelineList.tsx\uc785\ub2c8\ub2e4.<br>The section where pagination is applied is <code>TimelineList.tsx<\/code> in the theme directory.<\/p>\n\n\n\n<p>&#8212; app\/usersui\/[username]\/_components\/themes\/themeex\/TimelineList.tsx<\/p>\n\n\n\n<p>\u2714\ufe0f \ucd94\ud6c4 \ub098\uba38\uc9c0 \ubd80\ubd84\ub3c4 \ud398\uc774\uc9c0\ub124\uc774\uc158 \uc801\uc6a9\uc744 \ud560 \uc608\uc815\uc785\ub2c8\ub2e4.<br>We plan to implement pagination for the remaining sections as well.<\/p>\n\n\n\n<p>\u2714\ufe0f \ud398\uc774\uc9c0\ub124\uc774\uc158\uc758 \uac1c\ub150\uc744 \uc774\ud574\ud558\uae30 \uc704\ud574\uc11c  \ub77c\uc6b0\ud2b8 \uc2e4\ud589 \ud6c4 \uc2e4\uc81c\ub85c \ub370\uc774\ud130\uac00 \uc5b4\ub5bb\uac8c \ud758\ub7ec\uac00\ub294\uc9c0 \uc0b4\ud3b4 \ubcfc \ud544\uc694\uac00 \uc788\uc2b5\ub2c8\ub2e4.<br>To understand the concept of pagination, it is necessary to examine how data actually flows after a route is executed.<\/p>\n\n\n\n<p>\u2714\ufe0f \uc544\ub798\ub294 \ub370\uc774\ud130 \ud750\ub984 \uacbd\ub85c \uc124\uba85\uc785\ub2c8\ub2e4.<br>The following is a description of the data flow path.<\/p>\n\n\n\n<p>1)\ub77c\uc6b0\ud2b8\uac00 \uc2e4\ud589\ub418\uba74 page.tsx\ud30c\uc77c\uc744 \uc2e4\ud589\ud569\ub2c8\ub2e4.<br>When the route is executed, the page.tsx file is executed.<\/p>\n\n\n\n<p>A.\uc774 page.tsx\uc5d0\uc11c \uac00\uc785\ub418\uc9c0 \uc54a\uc740 \uc0ac\uc6a9\uc790 \uc774\ub984\uc73c\ub85c \uc811\uadfc\ud558\uba74 404(page not found)\uc624\ub958\ub97c \ubc1c\uc0dd \uc2dc\ud0b5\ub2c8\ub2e4.<br>In this <code>page.tsx<\/code>, accessing the page with a username that does not exist triggers a 404 (page not found) error.<\/p>\n\n\n\n<p>B. @username\uc774 \uac00\uc785\ub41c \uc0ac\uc6a9\uc790\uba74 ClientPage.tsx\ud30c\uc77c\uc744 \ud638\ucd9c \ud569\ub2c8\ub2e4.<br>If @username is a registered user, the ClientPage.tsx file is called.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \ub77c\uc6b0\ud2b8 \uc2e4\ud589 \uc8fc\uc18c(URl) \/ Route Execution URL\nhttps:\/\/aloy-horizon.duckdns.org\/@user1 or @your_user_name\n\n# page.tsx \ub514\ub809\ud1a0\ub9ac \uacbd\ub85c \/ page.tsx directory path\napp\/usersui\/&#91;username]\/page.tsx\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83d\udca1 \uc5ec\uae30\uc11c \ubd80\ud130\ub294 \uc561\ud2f0\ube0c \ud14c\ub9c8 \uc124\uba85\uc785\ub2c8\ub2e4.<br>The following is an explanation of the active theme.<\/p>\n\n\n\n<p>2)ClientPage.tsx\uc5d0\uc11c \uc561\ud2f0\ube0c \ud14c\ub9c8\ub97c \ud638\ucd9c\ud569\ub2c8\ub2e4.<br>Call the active theme in ClientPage.tsx.<\/p>\n\n\n\n<p>\u2714\ufe0f app\/usersui\/[username]\/ClientPage.tsx<\/p>\n\n\n\n<p>\u2714\ufe0f \ub85c\uadf8\uc778 \uc5ec\ubd80\uc5d0 \ub530\ub77c\uc11c \uc561\ud2f0\ube0c \ud14c\ub9c8\uc5d0 \ucd08\uae30\ub370\uc774\ud130, \ubd80\uc2a4\ud2b8, \uc88b\uc544\uc694, \uacf5\uc720\uae30\ub2a5\uc744 \uc561\ud2f0\ube0c \ud14c\ub9c8\uc5d0 \uc804\ub2ec\ud569\ub2c8\ub2e4.<br>Depending on the login status, initial data, boost, like, and share functions are passed to the active theme.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>  const props = { timeline, username, initialView, onBoost: handleBoost, onLike: handleLike, onShare: handleShare };\n\n  \n  \/\/ getThemeComponent : import { themeRegistry, getThemeComponent } from '.\/_components\/themes'; --&gt; index.ts\n\n  const ActiveTheme = getThemeComponent(theme as any) || themeRegistry.themeex?.component || themeRegistry&#91;themeNames&#91;0]]?.component;\n<\/code><\/pre>\n\n\n\n<p>3) \uc561\ud2f0\ube0c \ud14c\ub9c8 \ud638\ucd9c \ub85c\uc9c1<br>Active theme invocation logic<\/p>\n\n\n\n<p>\u2714\ufe0f \uc561\ud2f0\ube0c \ud14c\ub9c8\ub97c \ubd88\ub7ec\uc624\ub294 \ub85c\uc9c1\uc740 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<br>The logic for loading the active theme is as follows.<\/p>\n\n\n\n<p>A.ClientPage.tsx\uc5d0\uc11c index.ts\ud30c\uc77c\uc5d0 \uc800\uc7a5\ub41c getThemeComponent(theme as any) \ud568\uc218\ub97c \ud638\ucd9c\ud569\ub2c8\ub2e4.<br>ClientPage.tsx calls the <code>getThemeComponent(theme as any)<\/code> function stored in the index.ts file.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ClientPage.tsx<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>import { themeRegistry, getThemeComponent } from '.\/_components\/themes';\n... ...  \nconst ActiveTheme = getThemeComponent(theme as any)<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li> .\/_components\/themes\/index.ts<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># index.ts\ub294 \uc790\ub3d9\uc73c\ub85c \uc0dd\uc131\ub418\ub294 \ud30c\uc77c \/ index.ts is an automatically generated file.\n# \uc5ec\uae30\uc11c\ub294 themeex\ub97c \uae30\uc900\uc73c\ub85c \uc124\uba85\ud568. \/ The explanation here is based on themeex.\n\n# MainTheme.tsx\ub97c \ud638\ucd9c\ud574\uc11c \ub0b4\uc6a9\uc744 MainTheme\ubcc0\uc218\uc5d0 \uc800\uc7a5\ud558\uace0 themeexCompo\ubcc0\uc218\uc5d0 \uc800\uc7a5\nCall MainTheme.tsx, then store the content in the MainTheme variable and the themeexCompo variable.\n\n# themeRegistry\uc5d0 \ubaa8\ub450 MainTheme\ub97c \uc0ac\uc6a9\ud558\uba74 \ucda9\ub3cc\uc774 \uc788\uc73c\ubbc0\ub85c themeexComp\ucc98\ub7fc \ub2e4\ub978 \uc774\ub984\uc801\uc6a9\n# Since using MainTheme for everything in the themeRegistry causes conflicts, \n# apply a different name like themeexComp\n\n... ...\n\n\nimport { MainTheme as themeexComp} from '.\/themeex\/MainTheme';\n\n\n# component\ub294 \ud638\ucd9c\ub420 \ud568\uc218\ub85c themeexComp(=Maintheme)\ub97c \uc9c0\uc815\ud568.\n# The `component` specifies `themeexComp` (i.e., `Maintheme`) as the function to be called.\n\nexport const themeRegistry = {\n mastodon: { component: mastodonComp, label: 'mastodon' },\n minimal: { component: minimalComp, label: 'minimal' },\n pinafore: { component: pinaforeComp, label: 'pinafore' },\n themeex: { <strong>component: themeexComp,<\/strong> label: 'themeex' },\n} as const;\n\n# typeof : ...   pinafore: {...}, themeex: {...}\n# keyof  : 'mastodon' | 'minimal' | 'pinafore' | 'themeex'\n\nexport type ThemeName = keyof typeof themeRegistry;\n\n\n# \uc2e4\uc81c\ub85c themeRegistry\ubc30\uc5f4\uc5d0\uc11c themeex\ud574\ub2f9 \ud14c\ub9c8\uc758 component\uc778 MainTheme\ud568\uc218\ub97c \ub9ac\ud134\n# Actually returns the MainTheme function, which is the component of the corresponding theme, from the themeRegistry array themeex\n\nexport function getThemeComponent(name: ThemeName) {\n  return themeRegistry&#91;name]?.component;\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>MainTheme\ud568\uc218 props \/ MainTheme function props<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># ClientPage.tsx -&gt;\n# const props = { timeline, username, initialView, onBoost: handleBoost, onLike: handleLike, onShare: handleShare };\n\n# MainTheme.tsx\uc758 MainTheme\ud568\uc218\n# The MainTheme function in MainTheme.tsx\n\nexport function MainTheme({ <strong>timeline<\/strong> : initialTimeline, <strong>username<\/strong>, <strong>initialView<\/strong>, <strong>onBoost<\/strong>, <strong>onLike<\/strong>, <strong>onShare<\/strong> }: any) { ... }<\/code><\/pre>\n\n\n\n<p>\ud83d\udca1 \uc561\ud2f0\ube0c \ud14c\ub9c8 \uc124\uba85 \ub05d \/ End of active theme description.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>4)MainTheme.tsx\uc758 MainTheme\ud568\uc218\uc5d0 \uc804\ub2ec\ub41c props\ub4e4\uc740 \uc218\uc815\ud6c4 TimelineList.tsx\uc5d0 \uc804\ub2ec\ub429\ub2c8\ub2e4.<br>The props passed to the <code>MainTheme<\/code> function in <code>MainTheme.tsx<\/code> are passed to <code>TimelineList.tsx<\/code> after modification.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li style=\"font-size:16px\">username\uc740 @username\uac12\uc73c\ub85c \ub85c\uadf8\uc778\ud558\uc9c0 \uc54a\uc740 \uacbd\uc6b0 \ubcf4\uc5ec\uc904\ub370\uc774\ud130\ub098 \ub77c\uc6b0\ud2b8\ub97c \uc704\ud574\uc11c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<br>The <code>username<\/code> is used for data or routes to be displayed when the user has not logged in using the <code>@username<\/code> value.<br><\/li>\n\n\n\n<li style=\"font-size:16px\">onBoost,onLike\ub294 handleBoostClick, handleLikeClick\ud568\uc218\uc5d0 \ucd94\uac00\ub429\ub2c8\ub2e4.<br>onBoost and onLike are added to the handleBoostClick and handleLikeClick functions.<br><\/li>\n\n\n\n<li style=\"font-size:16px\">handleBoostClick,handLikeClick\ud568\uc218\ub294 \ub85c\uadf8\uc778\ud558\uc9c0 \uc54a\uc740 \uacbd\uc6b0 \ud074\ub9ad\ud558\uba74 \ub85c\uadf8\uc778 \ud398\uc774\uc9c0\ub85c \uc774\ub3d9\ud558\ub294 \uc5ed\ud560\uc744 \uc218\ud589\ud569\ub2c8\ub2e4.<br>The <code>handleBoostClick<\/code> and <code>handleLikeClick<\/code> functions redirect the user to the login page if they are not logged in.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nimport TimelineList from '.\/TimelineList'; \/\/ \u2705 myapp54\n... ...\n\n# MainTheme.tsx\uc758 MainTheme\ud568\uc218\n# The MainTheme function in MainTheme.tsx\n\nexport function MainTheme({ <strong>timeline<\/strong> : <strong>initialTimeline<\/strong>, username, initialView, <strong>onBoost<\/strong>, <strong>onLike<\/strong>, <strong>onShare<\/strong> }: any) { ... }\n\n... ...\n\n# \uc804\ub2ec \ubc1b\uc740 props\uac00 \ubcc0\uacbd\ub41c \ubd80\ubd84\n# Parts where received props have changed\n\nconst &#91;<strong>timeline<\/strong>, setTimeline] = useState&lt;any&#91;]&gt;(<strong>initialTimeline<\/strong> || &#91;]);\nconst <strong>handleBoostClick<\/strong> = async (p: any) =&gt; {\n  if (!currentUser) return window.location.href = `\/auth\/login?next=\/@${username}`;\n  <strong>onBoost<\/strong>(p)\n};\nconst <strong>handleLikeClick<\/strong> = (p: any) =&gt; {\n  if (!currentUser) return window.location.href = `\/auth\/login?next=\/@${username}`;\n  <strong>onLike<\/strong>(p);\n};\n\n... ...\n\n# TimelineList.tsx\uc5d0 props \uc804\ub2ec\n# Passing props to TimelineList.tsx\n\n          {view === 'timeline' &amp;&amp; (\n            &lt;&gt;\n            {\/* \u2705 myapp56 - ADD Dropdown(Home\/Local\/Federated Tabs ) *\/}\n\n              &lt;TimelineList\n                timeline={<strong>timeline<\/strong>}\n                tab={tab}\n                onTabChange={setTab}\n                currentUser={currentUser}\n                onDelete={handleDelete}\n                <strong>onBoost={handleBoostClick}<\/strong>\n                <strong>onLike={handleLikeClick}<\/strong>\n               <strong> onShare={onShare}<\/strong>\n              \/&gt;\n            &lt;\/&gt;\n          )} {\/* end view === 'timeline' *\/}\n<\/code><\/pre>\n\n\n\n<p>5)TimelineList.tsx<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li style=\"font-size:15px\">\uac01 onBoost,onLike,onShare\ud568\uc218\uac00 \ub0b4\uc7a5\ub41c \ubc84\ud2bc\uc744 \ud074\ub9ad\ud558\uba74 ClientPage.tsx\uc758 <strong> handleBoost, handleLike, handleShare <\/strong>\ud568\uc218\uac00 \uc2e4\ud589\ub429\ub2c8\ub2e4.<br>Clicking a button with the built-in <code>onBoost<\/code>, <code>onLike<\/code>, or <code>onShare<\/code> function triggers the corresponding <code>handleBoost<\/code>, <code>handleLike<\/code>, or <code>handleShare<\/code> function in <code>ClientPage.tsx<\/code>.<\/li>\n\n\n\n<li style=\"font-size:15px\">\uac01 \ucee8\ud150\uce20\ub294 .map((p: any, idx: number) => { \uc73c\ub85c \ud654\uba74\uc5d0 \ub370\uc774\ud130\ub97c \ud45c\uc2dc\ud569\ub2c8\ub2e4.<br>Each piece of content displays data on the screen using <code>.map((p: any, idx: number) => {<\/code>.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\nexport default function TimelineList({ \n  timeline: initialTimeline, currentUser, tab, onTabChange, onDelete, onBoost, onLike, onShare }: Props) { ... ...\n\n      {\/** \n       * p &amp;&amp; p.id.map(...) \n       * - p\uc640 p.id\uac00 \uc788\uc73c\uba74 map\ubd80\ubd84 \uc2e4\ud589 \/ If p and p.id exist, execute the map section.\n       * \n       * idx: number\n       * - map()\ud568\uc218\uc5d0\uc11c \uc790\ub3d9\uc73c\ub85c \uc81c\uacf5\ub418\ub294 \uc778\ub371\uc2a4(0\ubd80\ud130 \uc2dc\uc791)\n       * The index (starting from 0) automatically provided by the map() function.\n       * \n       *\/}\n\n      {data.filter((p:any) => p &amp;&amp; p.id).map((p: any, idx: number) => {\n        const uniqueKey = `${p.id}-${idx}`;\n\n        \/\/ \u2705 myapp61\n        const acct = p.account?.acct || '';\n        const username = p.account?.username || p.username || '';\n        const acctDomain = acct.includes('@')? acct.split('@')&#91;1] : DOMAIN;\n        const isLocalAccount = acctDomain === DOMAIN;\n        const isMine =!!(currentUser &amp;&amp; isLocalAccount &amp;&amp; username === currentUser &amp;&amp; p.account?.id!== `remote_${username}@${acctDomain}`);\n\n... ...\n\nreturn(\n... ...\n{\/* post*\/}\n              &lt;div className=\"flex gap-2 items-center flex-wrap\">\n                &lt;b className=\"text-\">{\/*\u2705 myapp61*\/ <strong>getDisplayName(p)<\/strong>}&lt;\/b>\n                &lt;span className=\"text-&#91;#999] text-xs\">@{ \/*\u2705 myapp61*\/<strong>getHandle(p)<\/strong> \n\/* new Date(p.created_at).toLocaleString()*\/}&lt;\/span>\n                {<strong>isRemote(p) &amp;&amp;<\/strong> &lt;span className=\"text-&#91;10px]\">\ud83c\udf0d&lt;\/span>}\n                {p.isBoostedPost &amp;&amp; &lt;span className=\"text-&#91;#16a34a] text-xs bg-&#91;#dcfce7] px-1.5 py-0.5 rounded\">\ud83d\udd01 <strong>{getDisplayName(p.actor)}<\/strong>&lt;\/span>}\n                \n\n                {\/* \u2705 myapp61 *\/}\n                {<strong>isMine &amp;&amp; <\/strong>(\n                  &lt;button onClick={() => onDelete(p.id)} className=\"text-&#91;#e0245e] ml-auto text-xs\">\n                    \ud83d\uddd1 Delete\n                  &lt;\/button>\n                )}\n\n              &lt;\/div>\n\n\n{\/* contents*\/}\n              &lt;div className=\"my-2 leading-&#91;1.4] break-words text- &#91;&amp;_p]:m-0\" dangerouslySetInnerHTML={{ __html: <strong>p.content<\/strong> }} \/>\n\n{\/* image *\/}\n              {p.media_attachments &amp;&amp; p.media_attachments.length > 0 &amp;&amp; (\n                &lt;div className={`grid gap-2 mt-2.5 rounded-xl overflow-hidden ${p.media_attachments.length === 1? 'grid-cols-1' : 'grid-cols-2'}`}>\n                  {p.media_attachments.map((m: any) => (\n                    &lt;img key={m.id} src={toAbsolute(m.preview_url || m.url)} alt=\"media\" loading=\"lazy\" className=\"w-full max-h- object-cover rounded-lg border border-&#91;#e6ecf0]\" \/>\n                  ))}\n                &lt;\/div>\n              )}\n\n\n\n{\/* boost, like, share *\/}\n              &lt;div className=\"flex gap-4 mt-2\">\n                &lt;button <strong>onClick={() => onBoost(p)} <\/strong>className={`bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333] ${p.isMyBoost? '!text-&#91;#1b9c59] font-bold bg-&#91;#dcfce7]' : ''}`}>\ud83d\udd01 {p.boostCount || ''}&lt;\/button>\n                &lt;button <strong>onClick={() => onLike(p)}<\/strong> className={`bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333] ${p.isMyLike? '!text-&#91;#e0245e] bg-&#91;#ffe4e6]' : ''}`}>\u2b50 {p.likeCount || ''}&lt;\/button>\n                &lt;button <strong>onClick={() => onShare(p)}<\/strong> className=\"bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333]\">\u2708&lt;\/button>\n                &lt;button className=\"bg-none border-none cursor-pointer text-&#91;#999] px-2 py-1 rounded-xl text-sm hover:bg-&#91;#f3f4f6] hover:text-&#91;#333]\">\ud83d\udcac&lt;\/button>\n              &lt;\/div>\n... ...\n\n\n); \/\/end return\n\n     })} \/\/ end timelielist function\n<\/code><\/pre>\n\n\n\n<p>6)\ud0c0\uc784\ub77c\uc778 API \ub370\uc774\ud130 \uc608\uc2dc \/ Timeline API Data Example<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li style=\"font-size:15px\">\uc544\ub798\ucc98\ub7fc \ud0c0\uc784\ub77c\uc778 API\ub97c \uc2e4\ud589\ud558\ub294 \uacbd\uc6b0 \uc608\uc2dc \ub370\uc774\ud130\uc785\ub2c8\ub2e4.(\ub85c\uadf8\uc778\ud55c \uacbd\uc6b0)<br>The following is example data for executing the Timeline API (when logged in).<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>https:&#47;&#47;aloy-horizon.duckdns.org\/api\/timeline?username=user1&amp;type=home<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>&#91;\n  {\n    \"id\": \"01M4J098H7BH1QZSDQ2B63V4WM\",\n    \"content\": \"\\u003Cp\\u003Egts public\\u003C\/p\\u003E\",\n    \"username\": \"user1\",\n    \"actor\": \"https:\/\/freelifemakers.com\/users\/user1\",\n    \"created_at\": \"2026-10-10T13:14:05+09:00\",\n    \"visibility\": \"public\",\n    \"type\": \"Note\",\n    \"source\": \"inbox\",\n    \"original_id\": \"https:\/\/freelifemakers.com\/users\/user1\/statuses\/01M4J098H7BH1QZSDQ2B63V4WM\",\n    \"fullId\": \"https:\/\/freelifemakers.com\/users\/user1\/statuses\/01M4J098H7BH1QZSDQ2B63V4WM\",\n    \"isMyBoost\": false,\n    \"boostCount\": 0,\n    \"isMyLike\": false,\n    \"likeCount\": 0,\n    \"isBoostedPost\": false,\n    \"isMine\": false\n  },\n  {\n    \"id\": \"5cdd75c8-1dfe-4acc-90e9-f24968a8e1f0\",\n    \"content\": \"local public\",\n    \"username\": \"user1\",\n    \"actor\": \"user1\",\n    \"created_at\": 1791605663435,\n    \"visibility\": \"public\",\n    \"type\": \"Note\",\n    \"source\": \"mine\",\n    \"original_id\": \"5cdd75c8-1dfe-4acc-90e9-f24968a8e1f0\",\n    \"fullId\": \"https:\/\/aloy-horizon.duckdns.org\/users\/user1\/statuses\/5cdd75c8-1dfe-4acc-90e9-f24968a8e1f0\",\n    \"isMyBoost\": false,\n    \"boostCount\": 0,\n    \"isMyLike\": false,\n    \"likeCount\": 0,\n    \"isBoostedPost\": false,\n    \"isMine\": true\n  },\n  {\n    \"id\": \"608e90d3-f138-47a3-afff-93239335bea8\",\n    \"content\": \"test4 private\",\n    \"username\": \"user1\",\n    \"actor\": \"user1\",\n    \"created_at\": 1791590136977,\n    \"visibility\": \"private\",\n    \"type\": \"Note\",\n    \"source\": \"mine\",\n    \"original_id\": \"608e90d3-f138-47a3-afff-93239335bea8\",\n    \"fullId\": \"https:\/\/aloy-horizon.duckdns.org\/users\/user1\/statuses\/608e90d3-f138-47a3-afff-93239335bea8\",\n    \"isMyBoost\": false,\n    \"boostCount\": 0,\n    \"isMyLike\": false,\n    \"likeCount\": 0,\n    \"isBoostedPost\": false,\n    \"isMine\": true\n  }\n]<\/code><\/pre>\n\n\n\n<p>\ud83d\udca1 \ub2e4\uc74c \ud3ec\uc2a4\ud2b8\uc5d0\uc11c \uacc4\uc18d \ub429\ub2c8\ub2e4. \/ To be continued in the next post.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\ub9c8\ud0dc\ubcf5\uc74c 21\uc7a5 22\uc808 \/ Matthew 21: 22<\/p>\n\n\n\n<p>&#8220;\ub108\ud76c\uac00 \uae30\ub3c4\ud560 \ub54c\uc5d0 \ubb34\uc5c7\uc774\ub4e0\uc9c0 \ubbff\uace0 \uad6c\ud558\ub294 \uac83\uc740 \ub2e4 \ubc1b\uc73c\ub9ac\ub77c \ud558\uc2dc\ub2c8\ub77c&#8221;<\/p>\n\n\n\n<p>&#8220;And everything you ask in prayer, believing, you will receive.&#8221;<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc5ec\uae30\uc11c\ub294 \uc561\ud2f0\ube0c\ud14c\ub9c8\uc640 \ud0c0\uc784\ub77c\uc778\uc758 \ucee4\uc11c \ud398\uc774\uc9c0 \ub124\uc774\uc158 \uad6c\uc870\ub97c \ubd84\uc11d\ud574 \ubd05\ub2c8\ub2e4.Here, we analyze the cursor-based pagination structure of Active Themes and Timelines. \ud83d\udc49\ud83c\udffb \ucee4\uc11c\ud398\uc774\uc9c0\ub124\uc774\uc158\uc740(\ud398\uc774\uc9c0 \ub124\uc774\uc158 + \ubb34\ud55c\uc2a4\ud06c\ub864)\uc785\ub2c8\ub2e4.Cursor-based pagination is a combination of pagination and infinite scrolling. \ud83d\udc49\ud83c\udffb \ubcf4\ud1b5 \uc6b0\ub9ac\uac00 \ubaa8\ubc14\uc77c \ud3f0\uc5d0\uc11c \uc2a4\ud06c\ub864\uc744 \uc544\ub798\ub85c \ub0b4\ub824\uc11c \ud654\uba74\ub05d\uc5d0 \ub3c4\ub2ec\ud558\uba74 \ub370\uc774\ud130\ub97c \ucd94\uac00\ub85c \ub4a4\uc5d0 \ubd99\uc774\ub294 \ubc29\uc2dd\uc744 \uc758\ubbf8\ud569\ub2c8\ub2e4.It typically refers to the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-12057","post","type-post","status-publish","format-standard","hentry","category-news","category-nextjs","category-uncategorized","category-website","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12057","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=12057"}],"version-history":[{"count":93,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12057\/revisions"}],"predecessor-version":[{"id":12152,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12057\/revisions\/12152"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=12057"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=12057"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=12057"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}