@naeil/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/messages/en.json +221 -0
- package/messages/ja.json +221 -0
- package/messages/ko.json +221 -0
- package/package.json +73 -0
- package/postcss.config.mjs +7 -0
- package/src/app/[locale]/(content)/baby-agent/page.tsx +30 -0
- package/src/app/[locale]/(content)/blog/page.tsx +68 -0
- package/src/app/[locale]/(content)/cc/page.tsx +216 -0
- package/src/app/[locale]/(content)/design/page.tsx +703 -0
- package/src/app/[locale]/(content)/layout.tsx +7 -0
- package/src/app/[locale]/(content)/pkm/page.tsx +31 -0
- package/src/app/[locale]/(content)/projects/page.tsx +100 -0
- package/src/app/[locale]/(content)/sa/page.tsx +179 -0
- package/src/app/[locale]/(landing)/page.tsx +157 -0
- package/src/app/[locale]/layout.tsx +72 -0
- package/src/app/[locale]/login/actions.ts +10 -0
- package/src/app/[locale]/login/oauth-buttons.tsx +78 -0
- package/src/app/[locale]/login/page.tsx +85 -0
- package/src/app/auth/callback/route.ts +78 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +32 -0
- package/src/app/layout.tsx +22 -0
- package/src/app/sitemap.ts +26 -0
- package/src/components/accent-picker.tsx +62 -0
- package/src/components/auth-slot.tsx +96 -0
- package/src/components/footer-wrapper.tsx +8 -0
- package/src/components/footer.tsx +193 -0
- package/src/components/hero-scene.tsx +948 -0
- package/src/components/hero-section.tsx +57 -0
- package/src/components/locale-switcher.tsx +74 -0
- package/src/components/logo.tsx +51 -0
- package/src/components/nav-server-wrapper.tsx +22 -0
- package/src/components/nav-wrapper.tsx +45 -0
- package/src/components/nav.tsx +550 -0
- package/src/components/paraglider-cursor.tsx +112 -0
- package/src/components/project-layout.tsx +194 -0
- package/src/components/theme-provider.tsx +10 -0
- package/src/components/theme-toggle-icon.tsx +62 -0
- package/src/components/theme-toggle.tsx +39 -0
- package/src/components/typography.tsx +27 -0
- package/src/components/ui/avatar.tsx +109 -0
- package/src/components/ui/badge.tsx +47 -0
- package/src/components/ui/button.tsx +65 -0
- package/src/components/ui/card.tsx +106 -0
- package/src/components/ui/dialog.tsx +158 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/sonner.tsx +54 -0
- package/src/components/workflow-diagram.tsx +414 -0
- package/src/i18n/config.ts +8 -0
- package/src/i18n/request.ts +16 -0
- package/src/i18n/routing.ts +12 -0
- package/src/lib/supabase/client.ts +18 -0
- package/src/lib/supabase/middleware.ts +42 -0
- package/src/lib/supabase/server.ts +37 -0
- package/src/lib/utils.ts +6 -0
- package/src/proxy.ts +62 -0
- package/src/tokens/.gitkeep +0 -0
- package/src/tokens/color.json +56 -0
- package/src/tokens/radius.json +9 -0
- package/src/tokens/semantic.json +81 -0
- package/src/tokens/shadow.json +7 -0
- package/src/tokens/spacing.json +16 -0
- package/src/tokens/typography.json +34 -0
- package/src/types/i18n.d.ts +6 -0
- package/src/utils/.gitkeep +0 -0
package/messages/ko.json
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
{
|
|
2
|
+
"common": {
|
|
3
|
+
"appName": "naeil",
|
|
4
|
+
"home": "홈",
|
|
5
|
+
"projects": "프로젝트",
|
|
6
|
+
"design": "디자인 시스템",
|
|
7
|
+
"loading": "로딩 중..."
|
|
8
|
+
},
|
|
9
|
+
"nav": {
|
|
10
|
+
"home": "홈",
|
|
11
|
+
"projects": "프로젝트",
|
|
12
|
+
"blog": "블로그"
|
|
13
|
+
},
|
|
14
|
+
"hero": {
|
|
15
|
+
"title": ".naeil",
|
|
16
|
+
"subtitle": "Build · Ship · Iterate"
|
|
17
|
+
},
|
|
18
|
+
"projects": {
|
|
19
|
+
"title": "프로젝트",
|
|
20
|
+
"subtitle": "실사용을 위해 만든 개인 도구들.",
|
|
21
|
+
"cc": {
|
|
22
|
+
"name": "Content Collector",
|
|
23
|
+
"description": "RSS, YouTube, Reddit 자동 수집 + AI 요약"
|
|
24
|
+
},
|
|
25
|
+
"pkm": {
|
|
26
|
+
"name": "PKM",
|
|
27
|
+
"description": "개인 지식 관리 — 문서 파싱, 임베딩, 시맨틱 검색"
|
|
28
|
+
},
|
|
29
|
+
"naeilUi": {
|
|
30
|
+
"name": "naeil-ui",
|
|
31
|
+
"description": "미니멀 디자인 시스템 — OKLCH 토큰, Tailwind v4, shadcn"
|
|
32
|
+
},
|
|
33
|
+
"babyAgent": {
|
|
34
|
+
"name": "Baby Agent",
|
|
35
|
+
"description": "육아 AI 에이전트 — LINE 기반 Q&A, 기록, 리마인더"
|
|
36
|
+
},
|
|
37
|
+
"status": {
|
|
38
|
+
"active": "활성",
|
|
39
|
+
"coming": "준비 중"
|
|
40
|
+
},
|
|
41
|
+
"sa": {
|
|
42
|
+
"name": "Sustainability Analyzer",
|
|
43
|
+
"description": "ESG 리포트 AI 분석 — PDF 파싱, 정성평가, 비교표 자동 생성"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"stack": {
|
|
47
|
+
"label": "사용 기술"
|
|
48
|
+
},
|
|
49
|
+
"cc": {
|
|
50
|
+
"name": "Content Collector",
|
|
51
|
+
"description": "로컬 AI 자동 파이프라인 — 흩어진 테크 소스, 하루 한 장으로",
|
|
52
|
+
"overview": "GitHub, Reddit, Threads — 여러 소스의 테크 콘텐츠를 수집하고 로컬 AI로 처리.\n\n임베딩, 분류, 클러스터링, 요약. 원시 콘텐츠에서 매일 편집된 다이제스트로.\n\nOllama + 무료 API 기반 전부 로컬 실행. PostgreSQL + pgvector 구조화 저장. 시맨틱 검색 내장.",
|
|
53
|
+
"features": {
|
|
54
|
+
"collect": {
|
|
55
|
+
"title": "멀티 소스 수집",
|
|
56
|
+
"desc": "RSS, Reddit, Threads — 한 파이프라인으로 수집·정규화"
|
|
57
|
+
},
|
|
58
|
+
"classify": {
|
|
59
|
+
"title": "로컬 AI 분류",
|
|
60
|
+
"desc": "Qwen3 14B 온디바이스 — 관련도 판별, 토픽 라벨링, 우선순위 랭킹"
|
|
61
|
+
},
|
|
62
|
+
"embed": {
|
|
63
|
+
"title": "벡터 임베딩 검색",
|
|
64
|
+
"desc": "BGE-M3 + pgvector — 의미 기반 유사 검색과 주제 추적"
|
|
65
|
+
},
|
|
66
|
+
"digest": {
|
|
67
|
+
"title": "데일리 다이제스트",
|
|
68
|
+
"desc": "Gemini 편집 요약 — LINE 메시지 + 상세 HTML 리포트"
|
|
69
|
+
},
|
|
70
|
+
"zeroCost": {
|
|
71
|
+
"title": "월 비용 0원",
|
|
72
|
+
"desc": "로컬 Mac Mini, 오픈 모델, 무료 API — 고정 인프라 비용 없음"
|
|
73
|
+
},
|
|
74
|
+
"alerts": {
|
|
75
|
+
"title": "실시간 알림",
|
|
76
|
+
"desc": "우선순위 높은 신호 감지 즉시 알림 — 몇 시간 뒤가 아니라 바로"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"workflow": {
|
|
80
|
+
"github": {
|
|
81
|
+
"desc": "RSS 피드를 통한 GitHub 릴리즈 및 디스커션 수집",
|
|
82
|
+
"meta": "30분 간격"
|
|
83
|
+
},
|
|
84
|
+
"reddit": {
|
|
85
|
+
"desc": "RSS 및 JSON 검색 API를 통한 서브레딧 포스트 수집",
|
|
86
|
+
"meta": "30분 간격"
|
|
87
|
+
},
|
|
88
|
+
"threads": {
|
|
89
|
+
"desc": "Playwright 헤드리스 브라우저로 프로필 스크래핑",
|
|
90
|
+
"meta": "30분 간격"
|
|
91
|
+
},
|
|
92
|
+
"collector": {
|
|
93
|
+
"desc": "소스별 디스패치, 콘텐츠 해시 중복 제거",
|
|
94
|
+
"meta": "SHA-256 중복 제거"
|
|
95
|
+
},
|
|
96
|
+
"postgres": {
|
|
97
|
+
"desc": "원본 아이템, 분류, 임베딩, 클러스터, 다이제스트 이력 저장"
|
|
98
|
+
},
|
|
99
|
+
"embed": {
|
|
100
|
+
"desc": "유사 검색을 위한 1024차원 다국어 벡터 생성",
|
|
101
|
+
"meta": "아이템당 ~2초"
|
|
102
|
+
},
|
|
103
|
+
"classify": {
|
|
104
|
+
"desc": "토픽, 중요도, 콘텐츠 유형, 태그 — 자동 라벨링",
|
|
105
|
+
"meta": "아이템당 ~18초"
|
|
106
|
+
},
|
|
107
|
+
"cluster": {
|
|
108
|
+
"desc": "코사인 유사도 그룹화, 핫 스코어 랭킹"
|
|
109
|
+
},
|
|
110
|
+
"digest": {
|
|
111
|
+
"desc": "상위 콘텐츠에서 편집 LINE 요약 + 상세 HTML 리포트 생성",
|
|
112
|
+
"meta": "무료 API"
|
|
113
|
+
},
|
|
114
|
+
"line": {
|
|
115
|
+
"desc": "LINE 그룹에 간결한 일일 요약 푸시"
|
|
116
|
+
},
|
|
117
|
+
"html": {
|
|
118
|
+
"desc": "링크와 점수 포함 카테고리별 상세 리포트"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"pkm": {
|
|
123
|
+
"name": "PKM",
|
|
124
|
+
"description": "개인 지식 베이스 — 문서 파싱, 임베딩, 시맨틱 검색"
|
|
125
|
+
},
|
|
126
|
+
"babyAgent": {
|
|
127
|
+
"name": "Baby Agent",
|
|
128
|
+
"description": "LINE 기반 육아 AI — Q&A, 성장 기록, 일정 리마인더"
|
|
129
|
+
},
|
|
130
|
+
"design": {
|
|
131
|
+
"title": "naeil-ui",
|
|
132
|
+
"subtitle": "디자인 시스템 쇼케이스 — 토큰 · 컴포넌트 · 테마"
|
|
133
|
+
},
|
|
134
|
+
"blogPage": {
|
|
135
|
+
"title": "블로그",
|
|
136
|
+
"subtitle": "빌드 기록, 리서치, 반복 개선 로그.",
|
|
137
|
+
"comingSoon": "준비 중"
|
|
138
|
+
},
|
|
139
|
+
"footer": {
|
|
140
|
+
"tagline": "Tomorrow starts here.",
|
|
141
|
+
"navigation": "네비게이션",
|
|
142
|
+
"projects": "프로젝트",
|
|
143
|
+
"blog": "블로그",
|
|
144
|
+
"social": "소셜"
|
|
145
|
+
},
|
|
146
|
+
"auth": {
|
|
147
|
+
"login": "로그인",
|
|
148
|
+
"loginWithGoogle": "Google로 로그인",
|
|
149
|
+
"loginWithGithub": "GitHub로 로그인",
|
|
150
|
+
"loginDescription": "모든 기능을 이용하려면 로그인하세요",
|
|
151
|
+
"redirecting": "리다이렉트 중...",
|
|
152
|
+
"logout": "로그아웃",
|
|
153
|
+
"profile": "프로필"
|
|
154
|
+
},
|
|
155
|
+
"locale": {
|
|
156
|
+
"switchLabel": "언어"
|
|
157
|
+
},
|
|
158
|
+
"sa": {
|
|
159
|
+
"name": "Sustainability Analyzer",
|
|
160
|
+
"description": "ESG 리포트를 AI로 분석 — 주제 발견, 정성평가, 기업간 비교표 자동 생성",
|
|
161
|
+
"overview": "기업 ESG 리포트 PDF를 파싱하고, AI로 체계적 정성평가를 수행하는 분석 파이프라인.\n\nDocling 레이아웃 파서로 표·텍스트 구조를 보존한 채 청킹. BGE-M3 임베딩(Dense+Sparse)으로 하이브리드 시맨틱 검색. Claude가 41개 ESG 주제를 자동 발견하고 415개 체크리스트 항목으로 정성평가를 수행.\n\n로컬 임베딩 + 무료 API 기반. PostgreSQL + pgvector에 구조화 저장.",
|
|
162
|
+
"features": {
|
|
163
|
+
"ingest": {
|
|
164
|
+
"title": "PDF 구조 보존 파싱",
|
|
165
|
+
"desc": "Docling 레이아웃 파서 — 표·섹션 경계를 보존한 계층적 청킹"
|
|
166
|
+
},
|
|
167
|
+
"embed": {
|
|
168
|
+
"title": "하이브리드 검색",
|
|
169
|
+
"desc": "BGE-M3 Dense+Sparse 임베딩 — pgvector 하이브리드 시맨틱 검색"
|
|
170
|
+
},
|
|
171
|
+
"topics": {
|
|
172
|
+
"title": "주제 자동 발견",
|
|
173
|
+
"desc": "Claude Sonnet — ESG 리포트에서 41개 주제·415개 체크리스트 자동 생성"
|
|
174
|
+
},
|
|
175
|
+
"assess": {
|
|
176
|
+
"title": "AI 정성평가",
|
|
177
|
+
"desc": "주제별 체크리스트 기반 자동 평가 — 근거 인용·점수·코멘트"
|
|
178
|
+
},
|
|
179
|
+
"compare": {
|
|
180
|
+
"title": "기업간 비교표",
|
|
181
|
+
"desc": "섹터별 필터링 — 주제×기업 매트릭스 자동 생성"
|
|
182
|
+
},
|
|
183
|
+
"zeroCost": {
|
|
184
|
+
"title": "로컬 + 무료",
|
|
185
|
+
"desc": "BGE-M3 온디바이스 임베딩, Claude·Gemini 무료 티어 활용"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"workflow": {
|
|
189
|
+
"pdf": {
|
|
190
|
+
"desc": "기업 ESG/지속가능성 리포트 PDF 입력",
|
|
191
|
+
"meta": "연간 리포트"
|
|
192
|
+
},
|
|
193
|
+
"docling": {
|
|
194
|
+
"desc": "레이아웃 기반 구조 파싱 — 표 단일 청킹, 섹션 경계 보존",
|
|
195
|
+
"meta": "표+텍스트"
|
|
196
|
+
},
|
|
197
|
+
"chunk": {
|
|
198
|
+
"desc": "Parent-Child 계층 청킹 — 문맥 보존 + 세밀 검색",
|
|
199
|
+
"meta": "parent 1K / child 512"
|
|
200
|
+
},
|
|
201
|
+
"bgem3": {
|
|
202
|
+
"desc": "Dense(1024d) + Sparse(학습된 BM25) 동시 임베딩 생성",
|
|
203
|
+
"meta": "FlagEmbedding"
|
|
204
|
+
},
|
|
205
|
+
"pgvector": {
|
|
206
|
+
"desc": "청크, 임베딩, 평가, 비교표 — 전체 구조화 저장"
|
|
207
|
+
},
|
|
208
|
+
"search": {
|
|
209
|
+
"desc": "Dense+Sparse 하이브리드 검색, Parent Context 확장"
|
|
210
|
+
},
|
|
211
|
+
"claude": {
|
|
212
|
+
"desc": "주제 발견, 체크리스트 생성, 근거 기반 정성평가",
|
|
213
|
+
"meta": "Sonnet"
|
|
214
|
+
},
|
|
215
|
+
"report": {
|
|
216
|
+
"desc": "주제×기업 비교표 HTML 리포트 자동 생성",
|
|
217
|
+
"meta": "섹터 필터"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@naeil/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"exports": {
|
|
5
|
+
"./components/*": "./src/components/*.tsx",
|
|
6
|
+
"./lib/*": "./src/lib/*.ts",
|
|
7
|
+
"./i18n/*": "./src/i18n/*.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "next dev",
|
|
11
|
+
"build": "next build",
|
|
12
|
+
"start": "next start",
|
|
13
|
+
"lint": "eslint",
|
|
14
|
+
"build:tokens": "tsx scripts/build-tokens.ts",
|
|
15
|
+
"check:contrast": "tsx scripts/check-contrast.ts"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@react-three/drei": "^10.7.7",
|
|
19
|
+
"@react-three/fiber": "^9.5.0",
|
|
20
|
+
"@supabase/ssr": "^0.9.0",
|
|
21
|
+
"@supabase/supabase-js": "^2.98.0",
|
|
22
|
+
"class-variance-authority": "^0.7.1",
|
|
23
|
+
"clsx": "^2.1.1",
|
|
24
|
+
"lucide-react": "^0.575.0",
|
|
25
|
+
"next": "16.1.6",
|
|
26
|
+
"next-intl": "^4.8.3",
|
|
27
|
+
"next-themes": "^0.4.6",
|
|
28
|
+
"pretendard": "^1.3.9",
|
|
29
|
+
"radix-ui": "^1.4.3",
|
|
30
|
+
"react": "19.2.3",
|
|
31
|
+
"react-dom": "19.2.3",
|
|
32
|
+
"sonner": "^2.0.7",
|
|
33
|
+
"tailwind-merge": "^3.5.0",
|
|
34
|
+
"three": "^0.183.2"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@tailwindcss/postcss": "^4",
|
|
38
|
+
"@types/node": "^20",
|
|
39
|
+
"@types/react": "^19",
|
|
40
|
+
"@types/react-dom": "^19",
|
|
41
|
+
"@types/three": "^0.183.1",
|
|
42
|
+
"eslint": "^9",
|
|
43
|
+
"eslint-config-next": "16.1.6",
|
|
44
|
+
"eslint-config-prettier": "^10.1.8",
|
|
45
|
+
"prettier": "^3.8.1",
|
|
46
|
+
"shadcn": "^3.8.5",
|
|
47
|
+
"style-dictionary": "^4.4.0",
|
|
48
|
+
"tailwindcss": "^4",
|
|
49
|
+
"tsx": "^4.21.0",
|
|
50
|
+
"tw-animate-css": "^1.4.0",
|
|
51
|
+
"typescript": "^5"
|
|
52
|
+
},
|
|
53
|
+
"pnpm": {
|
|
54
|
+
"onlyBuiltDependencies": [
|
|
55
|
+
"esbuild",
|
|
56
|
+
"style-dictionary",
|
|
57
|
+
"@bundled-es-modules/glob"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"files": [
|
|
61
|
+
"src/",
|
|
62
|
+
"messages/",
|
|
63
|
+
"tailwind.config.*",
|
|
64
|
+
"postcss.config.*"
|
|
65
|
+
],
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "https://github.com/naeil-dev/design-system"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { setRequestLocale } from "next-intl/server";
|
|
2
|
+
import { useTranslations } from "next-intl";
|
|
3
|
+
import { ProjectLayout } from "@/components/project-layout";
|
|
4
|
+
import type { ProjectData } from "@/components/project-layout";
|
|
5
|
+
|
|
6
|
+
export default async function BabyAgentPage({
|
|
7
|
+
params,
|
|
8
|
+
}: {
|
|
9
|
+
params: Promise<{ locale: string }>;
|
|
10
|
+
}) {
|
|
11
|
+
const { locale } = await params;
|
|
12
|
+
setRequestLocale(locale);
|
|
13
|
+
|
|
14
|
+
return <BabyAgentContent />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function BabyAgentContent() {
|
|
18
|
+
const t = useTranslations("babyAgent");
|
|
19
|
+
|
|
20
|
+
const data: ProjectData = {
|
|
21
|
+
icon: "/images/turtle.png",
|
|
22
|
+
name: t("name"),
|
|
23
|
+
description: t("description"),
|
|
24
|
+
accent: "oklch(0.769 0.188 70.08)",
|
|
25
|
+
tags: ["OpenClaw", "LINE", "AI Agent"],
|
|
26
|
+
comingSoon: true,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return <ProjectLayout data={data} />;
|
|
30
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { setRequestLocale } from "next-intl/server";
|
|
2
|
+
import { useTranslations } from "next-intl";
|
|
3
|
+
import { PageTitle } from "@/components/typography";
|
|
4
|
+
import Image from "next/image";
|
|
5
|
+
|
|
6
|
+
export default async function BlogPage({
|
|
7
|
+
params,
|
|
8
|
+
}: {
|
|
9
|
+
params: Promise<{ locale: string }>;
|
|
10
|
+
}) {
|
|
11
|
+
const { locale } = await params;
|
|
12
|
+
setRequestLocale(locale);
|
|
13
|
+
|
|
14
|
+
return <BlogContent />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function BlogContent() {
|
|
18
|
+
const t = useTranslations("blogPage");
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<section className="mx-auto max-w-4xl px-6 pb-16">
|
|
23
|
+
<div className="flex flex-col-reverse items-start gap-8 md:flex-row md:items-start md:justify-between">
|
|
24
|
+
<div className="flex-1">
|
|
25
|
+
<PageTitle className="mb-3">{t("title")}</PageTitle>
|
|
26
|
+
<p className="text-muted-foreground mb-5 max-w-lg text-lg leading-relaxed">
|
|
27
|
+
{t("subtitle")}
|
|
28
|
+
</p>
|
|
29
|
+
<div className="mb-6 flex flex-wrap gap-2">
|
|
30
|
+
{[
|
|
31
|
+
"Deep Dive",
|
|
32
|
+
"Research",
|
|
33
|
+
"Build Logs",
|
|
34
|
+
].map((tag) => (
|
|
35
|
+
<span
|
|
36
|
+
key={tag}
|
|
37
|
+
className="rounded-full border border-border-subtle px-2.5 py-1 text-[11px] text-zinc-400"
|
|
38
|
+
>
|
|
39
|
+
{tag}
|
|
40
|
+
</span>
|
|
41
|
+
))}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div className="flex-shrink-0">
|
|
46
|
+
<Image
|
|
47
|
+
src="/images/diver.png"
|
|
48
|
+
alt=""
|
|
49
|
+
width={220}
|
|
50
|
+
height={220}
|
|
51
|
+
className="animate-float object-contain"
|
|
52
|
+
style={{
|
|
53
|
+
filter:
|
|
54
|
+
"drop-shadow(0 4px 12px color-mix(in oklch, var(--project-naeilUi) 15%, transparent))",
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</section>
|
|
60
|
+
|
|
61
|
+
<section className="mx-auto max-w-4xl px-6 pb-24">
|
|
62
|
+
<div className="rounded-2xl border border-dashed border-border-subtle p-12 text-center">
|
|
63
|
+
<p className="text-muted-foreground text-sm">{t("comingSoon")}</p>
|
|
64
|
+
</div>
|
|
65
|
+
</section>
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { setRequestLocale } from "next-intl/server";
|
|
2
|
+
import { useTranslations } from "next-intl";
|
|
3
|
+
import { ProjectLayout } from "@/components/project-layout";
|
|
4
|
+
import type { ProjectData } from "@/components/project-layout";
|
|
5
|
+
|
|
6
|
+
export default async function CCPage({
|
|
7
|
+
params,
|
|
8
|
+
}: {
|
|
9
|
+
params: Promise<{ locale: string }>;
|
|
10
|
+
}) {
|
|
11
|
+
const { locale } = await params;
|
|
12
|
+
setRequestLocale(locale);
|
|
13
|
+
|
|
14
|
+
return <CCContent />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function CCContent() {
|
|
18
|
+
const t = useTranslations("cc");
|
|
19
|
+
|
|
20
|
+
const data: ProjectData = {
|
|
21
|
+
icon: "/images/coral.png",
|
|
22
|
+
name: t("name"),
|
|
23
|
+
description: t("description"),
|
|
24
|
+
accent: "oklch(0.704 0.140 181)",
|
|
25
|
+
tags: ["Python", "PostgreSQL", "Ollama", "Gemini", "LINE"],
|
|
26
|
+
github: "https://github.com/naeil-dev/content-collector",
|
|
27
|
+
|
|
28
|
+
overview: t("overview"),
|
|
29
|
+
|
|
30
|
+
features: [
|
|
31
|
+
{
|
|
32
|
+
icon: "📡",
|
|
33
|
+
title: t("features.collect.title"),
|
|
34
|
+
description: t("features.collect.desc"),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
icon: "🤖",
|
|
38
|
+
title: t("features.classify.title"),
|
|
39
|
+
description: t("features.classify.desc"),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
icon: "🧲",
|
|
43
|
+
title: t("features.embed.title"),
|
|
44
|
+
description: t("features.embed.desc"),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
icon: "📊",
|
|
48
|
+
title: t("features.digest.title"),
|
|
49
|
+
description: t("features.digest.desc"),
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
icon: "⚡",
|
|
53
|
+
title: t("features.zeroCost.title"),
|
|
54
|
+
description: t("features.zeroCost.desc"),
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
icon: "🔔",
|
|
58
|
+
title: t("features.alerts.title"),
|
|
59
|
+
description: t("features.alerts.desc"),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
|
|
63
|
+
workflow: {
|
|
64
|
+
nodes: [
|
|
65
|
+
{
|
|
66
|
+
id: "github",
|
|
67
|
+
label: "GitHub RSS",
|
|
68
|
+
type: "source",
|
|
69
|
+
position: { x: 20, y: 5 },
|
|
70
|
+
detail: {
|
|
71
|
+
description: t("workflow.github.desc"),
|
|
72
|
+
tech: ["feedparser", "httpx"],
|
|
73
|
+
meta: t("workflow.github.meta"),
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "reddit",
|
|
78
|
+
label: "Reddit",
|
|
79
|
+
type: "source",
|
|
80
|
+
position: { x: 50, y: 5 },
|
|
81
|
+
detail: {
|
|
82
|
+
description: t("workflow.reddit.desc"),
|
|
83
|
+
tech: ["RSS", "JSON API"],
|
|
84
|
+
meta: t("workflow.reddit.meta"),
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: "threads",
|
|
89
|
+
label: "Threads",
|
|
90
|
+
type: "source",
|
|
91
|
+
position: { x: 80, y: 5 },
|
|
92
|
+
detail: {
|
|
93
|
+
description: t("workflow.threads.desc"),
|
|
94
|
+
tech: ["Playwright", "httpx"],
|
|
95
|
+
meta: t("workflow.threads.meta"),
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: "collector",
|
|
100
|
+
label: "Collector",
|
|
101
|
+
type: "process",
|
|
102
|
+
position: { x: 50, y: 22 },
|
|
103
|
+
detail: {
|
|
104
|
+
description: t("workflow.collector.desc"),
|
|
105
|
+
tech: ["Python", "LaunchAgent"],
|
|
106
|
+
meta: t("workflow.collector.meta"),
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: "postgres",
|
|
111
|
+
label: "PostgreSQL",
|
|
112
|
+
type: "storage",
|
|
113
|
+
position: { x: 50, y: 38 },
|
|
114
|
+
detail: {
|
|
115
|
+
description: t("workflow.postgres.desc"),
|
|
116
|
+
tech: ["PostgreSQL 17", "pgvector", "Docker"],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "embed",
|
|
121
|
+
label: "BGE-M3",
|
|
122
|
+
type: "ai",
|
|
123
|
+
position: { x: 25, y: 53 },
|
|
124
|
+
detail: {
|
|
125
|
+
description: t("workflow.embed.desc"),
|
|
126
|
+
tech: ["Ollama", "BGE-M3"],
|
|
127
|
+
meta: t("workflow.embed.meta"),
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: "classify",
|
|
132
|
+
label: "Qwen3 14B",
|
|
133
|
+
type: "ai",
|
|
134
|
+
position: { x: 75, y: 53 },
|
|
135
|
+
detail: {
|
|
136
|
+
description: t("workflow.classify.desc"),
|
|
137
|
+
tech: ["Ollama", "Qwen3 14B"],
|
|
138
|
+
meta: t("workflow.classify.meta"),
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: "cluster",
|
|
143
|
+
label: "Cluster + Score",
|
|
144
|
+
type: "process",
|
|
145
|
+
position: { x: 50, y: 68 },
|
|
146
|
+
detail: {
|
|
147
|
+
description: t("workflow.cluster.desc"),
|
|
148
|
+
tech: ["pgvector", "cosine similarity"],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: "digest",
|
|
153
|
+
label: "Gemini Flash",
|
|
154
|
+
type: "ai",
|
|
155
|
+
position: { x: 50, y: 82 },
|
|
156
|
+
detail: {
|
|
157
|
+
description: t("workflow.digest.desc"),
|
|
158
|
+
tech: ["Gemini 2.5 Flash", "Jinja2"],
|
|
159
|
+
meta: t("workflow.digest.meta"),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "line",
|
|
164
|
+
label: "LINE Summary",
|
|
165
|
+
type: "output",
|
|
166
|
+
position: { x: 30, y: 95 },
|
|
167
|
+
detail: {
|
|
168
|
+
description: t("workflow.line.desc"),
|
|
169
|
+
tech: ["LINE Push API"],
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "html",
|
|
174
|
+
label: "HTML Digest",
|
|
175
|
+
type: "output",
|
|
176
|
+
position: { x: 70, y: 95 },
|
|
177
|
+
detail: {
|
|
178
|
+
description: t("workflow.html.desc"),
|
|
179
|
+
tech: ["Jinja2", "HTML"],
|
|
180
|
+
meta: "digest.naeil.dev",
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
edges: [
|
|
185
|
+
{ from: "github", to: "collector" },
|
|
186
|
+
{ from: "reddit", to: "collector" },
|
|
187
|
+
{ from: "threads", to: "collector" },
|
|
188
|
+
{ from: "collector", to: "postgres" },
|
|
189
|
+
{ from: "postgres", to: "embed" },
|
|
190
|
+
{ from: "postgres", to: "classify" },
|
|
191
|
+
{ from: "embed", to: "cluster" },
|
|
192
|
+
{ from: "classify", to: "cluster" },
|
|
193
|
+
{ from: "cluster", to: "digest" },
|
|
194
|
+
{ from: "digest", to: "line" },
|
|
195
|
+
{ from: "digest", to: "html" },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
stack: [
|
|
200
|
+
{ icon: "🐍", name: "Python 3.12" },
|
|
201
|
+
{ icon: "🐘", name: "PostgreSQL 17" },
|
|
202
|
+
{ icon: "🧮", name: "pgvector" },
|
|
203
|
+
{ icon: "🦙", name: "Ollama" },
|
|
204
|
+
{ icon: "🤖", name: "Qwen3 14B" },
|
|
205
|
+
{ icon: "🔤", name: "BGE-M3" },
|
|
206
|
+
{ icon: "✨", name: "Gemini 2.5 Flash" },
|
|
207
|
+
{ icon: "📱", name: "LINE API" },
|
|
208
|
+
{ icon: "🤖", name: "Telegram Bot API" },
|
|
209
|
+
{ icon: "🐳", name: "Docker Compose" },
|
|
210
|
+
{ icon: "⏰", name: "LaunchAgent" },
|
|
211
|
+
{ icon: "🎭", name: "Playwright" },
|
|
212
|
+
],
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return <ProjectLayout data={data} />;
|
|
216
|
+
}
|