[nextjs]SNS Server-16(myapp26)

👉🏻 myapp26에는 스킨기능을 구현합니다.
Skin functionality is implemented in myapp26.

👉🏻 코드 양이 많아서 주요 부분만 설명합니다 .
Due to the large volume of code, I will explain only the key parts.

👉🏻 전체코드는 깃허브 코드를 참조하세요
Please refer to the GitHub repository for the full code.

https://github.com/gideonslife01/flm-nextjs

📁 전체 프로젝트 구조 / Overall Project Structure

myapp26/  
├── app/  (Next.js App Router)
│   ├── .well-known/webfinger/route.ts  -> webfinger
│   ├── api/follow/route.ts    -> Follow API(temporary)
│   ├── api/announce/route.ts  -> Boost(Announcement)
│   ├── api/like/route.ts.     -> Like API
│   ├── api/posts/route.ts     -> Writing API
│   ├── api/timeline/route.ts  -> Timeline API
│   ├── users/[username]/
│   │   ├── statuses/[id]/route.ts -> Indivisual Post
│   │   ├── route.ts               -> Acotr Information
│   │   ├── followers/route.ts     -> Followers List
│   │   ├── following/route.ts     -> Following List
│   │   ├── inbox/route.ts         -> Inbox
│   │   └── outbox/route.ts        -> outbox
│   ├── usersui/[username]/
│   │   ├── page.tsx               -> Timeline UI
│   │   └── _components/themes/
│   │       ├── pinafore/Pinaforetheme.tsx  -> Theme 1
│   │       ├── mastodon/Mastodontheme.tsx  -> Theme 2
│   │       └── minimal/Minimaltheme.tsx    -> Theme 3
│   ├── layout.tsx, page.tsx, globals.css
│   └── favicon.ico
├── lib/
│   ├── theme.tsx              -> Theme Provider
│   ├── ap.ts                  -> Follow Accept
│   └── db.ts                  -> DB connection
├── data/
│   └── keys/                  -> private.pem, public.pem
├── data.sqlite                -> Database
├── Caddyfile                  -> https 
└── package.json

📁 프로젝트 시작(myapp26)
Project Start (myapp26)

npx create-next-app@latest

📁 SQLite설치 / Installing SQLite

cd ~/myapp26
npm install better-sqlite3
npm install -D @types/better-sqlite3

📁 DDNS,https설정 / DDNS,https settings

📁 도메인허용, @userid 사용하기
Allowing domains, using @userid

— next.config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* allow domain*/
  allowedDevOrigins: ['aloy-horizon.duckdns.org', '*.duckdns.org'],

  /* host.domain.org/@userid */
  async rewrites() {
    return [
      {
        source: '/@:username',
        destination: '/usersui/:username',
      },
    ]
  }
};


export default nextConfig;

📁 코드수정 / Code Modification

✔️ myapp26/lib/theme.tsx파일을 불러와 컨텍스트 프로바이더를 적용합니다.
Import the myapp26/lib/theme.tsx file and apply the context provider.

💡 컨텍스트 프로바이더는 하나의 이벤트로 전체 상태를 변경하는 기능으로 테마적용이나 언어 적용 설정에 많이 사용됩니다.
A Context Provider is a feature that allows the entire state to be updated via a single event; it is commonly used for settings such as applying themes or languages.

— myapp26/app/usersui/[username]/Layout.tsx

import { ThemeProvider } from "@/lib/theme"; // ✅ myapp26

... ...

export default function RootLayout({ children }: LayoutProps<"/">) {
  return (
    <html
      lang="en"
      className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
    >
      <body className="min-h-full flex flex-col">
        {/* ✅ myapp26 - Add ThemeProvide */}
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

✔️ 여기서 테마파일을 불러오고 테마(스킨)을적용합니다.
Here, you load the theme file and apply the theme (skin).

— myapp26/app/paget.tsx

... ...
import { PinaforeTheme } from './_components/themes/pinafore/Pinaforetheme';
import { MastodonTheme } from './_components/themes/mastodon/Mastodontheme';
import { MinimalTheme } from './_components/themes/minimal/Minimaltheme';
... ...

  // ✅ timeline fetch
  useEffect(() => {
    params.then(p => {
      setUsername(p.username);
      fetch(`/api/timeline?username=${p.username}`)
        .then(r => r.json())
        .then(data => {
          setTimeline(data);
          setLoading(false);
        });
    });
  }, [params]);
... ...
  if (loading) return <div style={{ padding: 20 }}>Loading...</div>;

  // ✅ theme 분기 + props 전달 / Theme branching + props passing
  const props = { timeline, username, onBoost: handleBoost, onLike: handleLike };

  // apply theme
  if (theme === 'pinafore') return <PinaforeTheme {...props} />
  if (theme === 'mastodon') return <MastodonTheme {...props} />
  if (theme === 'minimal') return <MinimalTheme {...props} />
  
  return <PinaforeTheme {...props} />;

📁 디렉토리 및 파일 추가 / Add directories and files

✔️ 타임라인 스킨(테마) UI / Timeline Skin (Theme) UI

— 아래의 파일은 모두 테마 디자인으로 좋아요,부스트기능은 빠져있습니다.
The files below are all theme designs; the boost function is not included.

myapp26/app/usersui/[username]/_components/themes/pinafore/Pinaforetheme.tsx

myapp26/app/usersui/[username]/_components/themes/mastodon/Mastodontheme.tsx

myapp26/app/usersui/[username]/_components/themes/minimal/Minimaltheme.tsx

— 세 파일 모두 동일하며 테마의 구분이 가능하게 테마 이름만 표시줬습니다.
All three files are identical; only the theme names are displayed to distinguish between them.

<h2>🐘 {username}/ Pinafore</h2> {/* 테마이름 / Theme Name */}
Pinafore theme
Mastodon theme

— 테마 변수의 값이 변하면 컨텍스트 프로바이더에서 로컬 스토리지의 값을 변경합니다.
When the value of the theme variable changes, the context provider updates the value in local storage.

... ...
const [theme, setTheme] = useState<ThemeName>('pinafore');
... ...         
<select 
            value={theme} //  현재 로컬스토리지 값 표시 / Display current local storage value
            onChange={(e) => {
            setTheme(e.target.value as any); 
         }}>
            <option value="pinafore">Pinafore</option>
            <option value="mastodon">Mastodon</option>
            <option value="minimal">Minimal</option>
          </select>
Minimal
Browser Local storage

✔️ 컨텍스트 프로바이더 / Context Provider

— myapp26/lib/theme.tsx

... ...
  useEffect(() => {
    const saved = localStorage.getItem('theme') as ThemeName;
    if (saved) setTheme(saved);
  }, []);
... ...  

return (
    <ThemeContext.Provider value={{ theme, setTheme: updateTheme }}>
      <div data-theme={theme} style={{ minHeight: '100%', display: 'flex', flexDirection: 'column', flex: 1 }}>
        {children}
      </div>
    </ThemeContext.Provider>
  );

1)컨텍스트 프로바이더에 theme변수를 파라메터로 적용합니다.
Apply the theme variable as a parameter to the context provider.

2)theme 값이 변경되면 다른 테마파일을 불러오기 위해서 사용됩니다.
It is used to load a different theme file when the theme value changes.

3)테마이름은 브라우저의 로컬 스토리지에 저장됩니다.
The theme name is stored in the browser’s local storage.

요한복음 8장 32절 / John 8:32

“그리고 너희는 진리를 알게 될 것이며, 진리가 너희를 자유롭게 할 것이다.”

“Then you will know the truth ,and the truth will set you free”

Leave a Reply