@naeil/ui 0.9.0 → 0.10.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/CHANGELOG.md +7 -0
- package/dist/{chunk-XRO3NJAB.js → chunk-F7XM5HJ4.js} +40 -154
- package/dist/{chunk-JDHGKM25.js → chunk-GQO6NMXK.js} +267 -2
- package/dist/components/index.js +12 -3
- package/dist/components/naeil-footer.d.ts +3 -3
- package/dist/components/naeil-footer.js +14 -11
- package/dist/components/naeil-header.d.ts +7 -9
- package/dist/components/naeil-header.js +2 -2
- package/dist/lib/ui-release.d.ts +1 -1
- package/dist/lib/ui-release.js +1 -1
- package/dist/naeil-locale/checker.d.ts +16 -0
- package/dist/naeil-locale/checker.js +91 -0
- package/dist/naeil-locale/chrome.d.ts +150 -0
- package/dist/naeil-locale/chrome.js +2385 -0
- package/dist/naeil-locale/chunk-D37JHNUN.js +56 -0
- package/dist/naeil-locale/chunk-N3ETBM74.js +24 -0
- package/dist/naeil-locale/chunk-QWHIELL2.js +161 -0
- package/dist/naeil-locale/chunk-YQ5OJWBF.js +53 -0
- package/dist/naeil-locale/client.d.ts +70 -0
- package/dist/naeil-locale/client.js +382 -0
- package/dist/naeil-locale/en-ZC66VDHP.js +86 -0
- package/dist/naeil-locale/index.d.ts +40 -0
- package/dist/naeil-locale/index.js +111 -0
- package/dist/naeil-locale/ja-DKIEQUG7.js +86 -0
- package/dist/naeil-locale/ko-CY6663RZ.js +86 -0
- package/dist/naeil-locale/messages-BQ-fnCAJ.d.ts +166 -0
- package/dist/naeil-locale/messages.d.ts +1 -0
- package/dist/naeil-locale/messages.js +14 -0
- package/dist/naeil-locale/server.d.ts +75 -0
- package/dist/naeil-locale/server.js +172 -0
- package/dist/source/components/naeil-footer-core.d.ts +16 -0
- package/dist/source/components/naeil-footer-core.js +93 -0
- package/dist/source/components/naeil-footer.d.ts +6 -11
- package/dist/source/components/naeil-footer.js +4 -75
- package/dist/source/components/naeil-header-account-core.d.ts +26 -0
- package/dist/source/components/naeil-header-account-core.js +98 -0
- package/dist/source/components/naeil-header-account.d.ts +6 -22
- package/dist/source/components/naeil-header-account.js +5 -81
- package/dist/source/components/naeil-header-content.d.ts +102 -109
- package/dist/source/components/naeil-header-content.js +6 -142
- package/dist/source/components/naeil-header-core.d.ts +59 -0
- package/dist/source/components/naeil-header-core.js +231 -0
- package/dist/source/components/naeil-header-data.d.ts +11 -0
- package/dist/source/components/naeil-header-data.js +14 -0
- package/dist/source/components/naeil-header.d.ts +10 -51
- package/dist/source/components/naeil-header.js +9 -200
- package/dist/source/components/naeil-messages-context.d.ts +94 -0
- package/dist/source/components/naeil-messages-context.js +16 -0
- package/dist/source/components/naeil-standalone-messages.d.ts +11 -0
- package/dist/source/components/naeil-standalone-messages.js +13 -0
- package/dist/source/i18n/routing.d.ts +22 -20
- package/dist/source/lib/ui-release.d.ts +1 -1
- package/dist/source/lib/ui-release.js +1 -1
- package/dist/source/naeil-locale/messages/en.json +78 -0
- package/dist/source/naeil-locale/messages/ja.json +78 -0
- package/dist/source/naeil-locale/messages/ko.json +78 -0
- package/docs/components/naeil-locale.md +46 -0
- package/docs/package-release.md +11 -0
- package/package.json +34 -6
- /package/dist/{naeil-header-content-BvISJ4RV.d.ts → naeil-header-data-BvISJ4RV.d.ts} +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { NaeilHeaderLocale } from './naeil-header-data.js';
|
|
4
|
+
|
|
5
|
+
/** Only the standalone compatibility entry includes all three small dictionaries. */
|
|
6
|
+
declare function NaeilStandaloneMessages({ locale, children }: {
|
|
7
|
+
locale: NaeilHeaderLocale;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}): react_jsx_runtime.JSX.Element;
|
|
10
|
+
|
|
11
|
+
export { NaeilStandaloneMessages };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import en from "../naeil-locale/messages/en.json";
|
|
4
|
+
import ko from "../naeil-locale/messages/ko.json";
|
|
5
|
+
import ja from "../naeil-locale/messages/ja.json";
|
|
6
|
+
import { NaeilMessagesProvider } from "./naeil-messages-context.js";
|
|
7
|
+
const messages = { en: en.naeil, ko: ko.naeil, ja: ja.naeil };
|
|
8
|
+
function NaeilStandaloneMessages({ locale, children }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(NaeilMessagesProvider, { locale, messages: messages[locale], children });
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
NaeilStandaloneMessages
|
|
13
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as next_dist_shared_lib_app_router_context_shared_runtime from 'next/dist/shared/lib/app-router-context.shared-runtime';
|
|
2
|
-
import * as
|
|
2
|
+
import * as next_dist_client_components_redirect_error from 'next/dist/client/components/redirect-error';
|
|
3
3
|
import * as next_intl_navigation from 'next-intl/navigation';
|
|
4
4
|
import * as url from 'url';
|
|
5
5
|
import * as react from 'react';
|
|
@@ -31,8 +31,6 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
31
31
|
style?: react.CSSProperties | undefined;
|
|
32
32
|
title?: string | undefined | undefined;
|
|
33
33
|
locale?: string | undefined;
|
|
34
|
-
onError?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
35
|
-
children?: react.ReactNode;
|
|
36
34
|
ref?: react.Ref<HTMLAnchorElement> | undefined;
|
|
37
35
|
prefix?: string | undefined | undefined;
|
|
38
36
|
key?: react.Key | null | undefined;
|
|
@@ -42,12 +40,10 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
42
40
|
passHref?: boolean | undefined;
|
|
43
41
|
prefetch?: boolean | "auto" | null | undefined;
|
|
44
42
|
legacyBehavior?: boolean | undefined;
|
|
45
|
-
onMouseEnter?: React.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
46
|
-
onTouchStart?: React.TouchEventHandler<HTMLAnchorElement> | undefined;
|
|
47
|
-
onClick?: React.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
48
43
|
onNavigate?: ((event: {
|
|
49
44
|
preventDefault: () => void;
|
|
50
45
|
}) => void) | undefined;
|
|
46
|
+
transitionTypes?: string[] | undefined;
|
|
51
47
|
download?: any;
|
|
52
48
|
hrefLang?: string | undefined | undefined;
|
|
53
49
|
media?: string | undefined | undefined;
|
|
@@ -104,7 +100,6 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
104
100
|
is?: string | undefined | undefined;
|
|
105
101
|
exportparts?: string | undefined | undefined;
|
|
106
102
|
part?: string | undefined | undefined;
|
|
107
|
-
tw?: string | undefined;
|
|
108
103
|
"aria-activedescendant"?: string | undefined | undefined;
|
|
109
104
|
"aria-atomic"?: (boolean | "true" | "false") | undefined;
|
|
110
105
|
"aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -158,6 +153,8 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
158
153
|
"aria-valuemin"?: number | undefined | undefined;
|
|
159
154
|
"aria-valuenow"?: number | undefined | undefined;
|
|
160
155
|
"aria-valuetext"?: string | undefined | undefined;
|
|
156
|
+
href: string | url.UrlObject;
|
|
157
|
+
children?: react.ReactNode;
|
|
161
158
|
dangerouslySetInnerHTML?: {
|
|
162
159
|
__html: string | TrustedHTML;
|
|
163
160
|
} | undefined | undefined;
|
|
@@ -177,20 +174,21 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
177
174
|
onFocusCapture?: react.FocusEventHandler<HTMLAnchorElement> | undefined;
|
|
178
175
|
onBlur?: react.FocusEventHandler<HTMLAnchorElement> | undefined;
|
|
179
176
|
onBlurCapture?: react.FocusEventHandler<HTMLAnchorElement> | undefined;
|
|
180
|
-
onChange?: react.
|
|
181
|
-
onChangeCapture?: react.
|
|
177
|
+
onChange?: react.ChangeEventHandler<HTMLAnchorElement, Element> | undefined;
|
|
178
|
+
onChangeCapture?: react.ChangeEventHandler<HTMLAnchorElement, Element> | undefined;
|
|
182
179
|
onBeforeInput?: react.InputEventHandler<HTMLAnchorElement> | undefined;
|
|
183
|
-
onBeforeInputCapture?: react.
|
|
184
|
-
onInput?: react.
|
|
185
|
-
onInputCapture?: react.
|
|
186
|
-
onReset?: react.
|
|
187
|
-
onResetCapture?: react.
|
|
188
|
-
onSubmit?: react.
|
|
189
|
-
onSubmitCapture?: react.
|
|
190
|
-
onInvalid?: react.
|
|
191
|
-
onInvalidCapture?: react.
|
|
180
|
+
onBeforeInputCapture?: react.InputEventHandler<HTMLAnchorElement> | undefined;
|
|
181
|
+
onInput?: react.InputEventHandler<HTMLAnchorElement> | undefined;
|
|
182
|
+
onInputCapture?: react.InputEventHandler<HTMLAnchorElement> | undefined;
|
|
183
|
+
onReset?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
184
|
+
onResetCapture?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
185
|
+
onSubmit?: react.SubmitEventHandler<HTMLAnchorElement> | undefined;
|
|
186
|
+
onSubmitCapture?: react.SubmitEventHandler<HTMLAnchorElement> | undefined;
|
|
187
|
+
onInvalid?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
188
|
+
onInvalidCapture?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
192
189
|
onLoad?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
193
190
|
onLoadCapture?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
191
|
+
onError?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
194
192
|
onErrorCapture?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
195
193
|
onKeyDown?: react.KeyboardEventHandler<HTMLAnchorElement> | undefined;
|
|
196
194
|
onKeyDownCapture?: react.KeyboardEventHandler<HTMLAnchorElement> | undefined;
|
|
@@ -244,6 +242,7 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
244
242
|
onWaitingCapture?: react.ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
245
243
|
onAuxClick?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
246
244
|
onAuxClickCapture?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
245
|
+
onClick?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
247
246
|
onClickCapture?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
248
247
|
onContextMenu?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
249
248
|
onContextMenuCapture?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
@@ -267,6 +266,7 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
267
266
|
onDropCapture?: react.DragEventHandler<HTMLAnchorElement> | undefined;
|
|
268
267
|
onMouseDown?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
269
268
|
onMouseDownCapture?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
269
|
+
onMouseEnter?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
270
270
|
onMouseLeave?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
271
271
|
onMouseMove?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
272
272
|
onMouseMoveCapture?: react.MouseEventHandler<HTMLAnchorElement> | undefined;
|
|
@@ -284,6 +284,7 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
284
284
|
onTouchEndCapture?: react.TouchEventHandler<HTMLAnchorElement> | undefined;
|
|
285
285
|
onTouchMove?: react.TouchEventHandler<HTMLAnchorElement> | undefined;
|
|
286
286
|
onTouchMoveCapture?: react.TouchEventHandler<HTMLAnchorElement> | undefined;
|
|
287
|
+
onTouchStart?: react.TouchEventHandler<HTMLAnchorElement> | undefined;
|
|
287
288
|
onTouchStartCapture?: react.TouchEventHandler<HTMLAnchorElement> | undefined;
|
|
288
289
|
onPointerDown?: react.PointerEventHandler<HTMLAnchorElement> | undefined;
|
|
289
290
|
onPointerDownCapture?: react.PointerEventHandler<HTMLAnchorElement> | undefined;
|
|
@@ -325,7 +326,6 @@ declare const Link: react.ForwardRefExoticComponent<Omit<{
|
|
|
325
326
|
onTransitionRunCapture?: react.TransitionEventHandler<HTMLAnchorElement> | undefined;
|
|
326
327
|
onTransitionStart?: react.TransitionEventHandler<HTMLAnchorElement> | undefined;
|
|
327
328
|
onTransitionStartCapture?: react.TransitionEventHandler<HTMLAnchorElement> | undefined;
|
|
328
|
-
href: string | url.UrlObject;
|
|
329
329
|
}, "ref"> & react.RefAttributes<HTMLAnchorElement>>;
|
|
330
330
|
declare const redirect: (args: {
|
|
331
331
|
href: string | {
|
|
@@ -334,7 +334,7 @@ declare const redirect: (args: {
|
|
|
334
334
|
};
|
|
335
335
|
locale: string;
|
|
336
336
|
forcePrefix?: boolean;
|
|
337
|
-
}, type?:
|
|
337
|
+
}, type?: next_dist_client_components_redirect_error.RedirectType | undefined) => never;
|
|
338
338
|
declare const usePathname: () => string;
|
|
339
339
|
declare const useRouter: () => {
|
|
340
340
|
push: (href: string | {
|
|
@@ -358,6 +358,8 @@ declare const useRouter: () => {
|
|
|
358
358
|
back(): void;
|
|
359
359
|
forward(): void;
|
|
360
360
|
refresh(): void;
|
|
361
|
+
experimental_gesturePush?(href: string, options?: next_dist_shared_lib_app_router_context_shared_runtime.NavigateOptions): void;
|
|
362
|
+
bfcacheId: string;
|
|
361
363
|
};
|
|
362
364
|
declare const getPathname: (args: {
|
|
363
365
|
href: string | {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"naeil": {
|
|
3
|
+
"header": {
|
|
4
|
+
"nav": {
|
|
5
|
+
"home": "Home",
|
|
6
|
+
"projects": "Projects",
|
|
7
|
+
"blog": "Blog",
|
|
8
|
+
"navigation": "Main navigation",
|
|
9
|
+
"menu": "Menu",
|
|
10
|
+
"closeMenu": "Close menu"
|
|
11
|
+
},
|
|
12
|
+
"theme": {
|
|
13
|
+
"switchToLight": "Switch to light theme",
|
|
14
|
+
"switchToDark": "Switch to dark theme"
|
|
15
|
+
},
|
|
16
|
+
"locale": {
|
|
17
|
+
"switchLabel": "Language"
|
|
18
|
+
},
|
|
19
|
+
"projects": {
|
|
20
|
+
"cc": {
|
|
21
|
+
"name": "Content Collector",
|
|
22
|
+
"description": "Automated content collection from RSS, YouTube, Reddit + AI summarization"
|
|
23
|
+
},
|
|
24
|
+
"pkm": {
|
|
25
|
+
"name": "PKM",
|
|
26
|
+
"description": "Personal knowledge management — document parsing, embeddings, semantic search"
|
|
27
|
+
},
|
|
28
|
+
"naeilUi": {
|
|
29
|
+
"name": "naeil-ui",
|
|
30
|
+
"description": "Minimal design system — OKLCH tokens, Tailwind v4, shadcn"
|
|
31
|
+
},
|
|
32
|
+
"sa": {
|
|
33
|
+
"name": "Sustainability Analyzer",
|
|
34
|
+
"description": "AI-powered ESG report analysis — PDF parsing, qualitative assessment, comparison tables"
|
|
35
|
+
},
|
|
36
|
+
"babyAgent": {
|
|
37
|
+
"name": "Baby Agent",
|
|
38
|
+
"description": "Parenting AI agent — LINE-based Q&A, records, reminders"
|
|
39
|
+
},
|
|
40
|
+
"status": {
|
|
41
|
+
"active": "Active",
|
|
42
|
+
"coming": "Coming Soon"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"account": {
|
|
47
|
+
"menu": "Account menu",
|
|
48
|
+
"account": "Account",
|
|
49
|
+
"login": "Log in",
|
|
50
|
+
"logout": "Log out",
|
|
51
|
+
"busy": "Logging out…"
|
|
52
|
+
},
|
|
53
|
+
"footer": {
|
|
54
|
+
"navigation": "Navigation",
|
|
55
|
+
"projects": "Projects",
|
|
56
|
+
"blog": "Blog",
|
|
57
|
+
"social": "Social",
|
|
58
|
+
"description": "Tomorrow starts here."
|
|
59
|
+
},
|
|
60
|
+
"locale": {
|
|
61
|
+
"names": {
|
|
62
|
+
"en": "English",
|
|
63
|
+
"ko": "한국어",
|
|
64
|
+
"ja": "日本語"
|
|
65
|
+
},
|
|
66
|
+
"pending": "Changing language…",
|
|
67
|
+
"failed": "The language could not be changed. Your work is still here.",
|
|
68
|
+
"retry": "Try again",
|
|
69
|
+
"errors": {
|
|
70
|
+
"badRequest": "This address is not valid.",
|
|
71
|
+
"notFound": "Page not found.",
|
|
72
|
+
"unauthenticated": "Sign in to continue.",
|
|
73
|
+
"forbidden": "You do not have access to this page.",
|
|
74
|
+
"unavailable": "The service is temporarily unavailable. Please try again."
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"naeil": {
|
|
3
|
+
"header": {
|
|
4
|
+
"nav": {
|
|
5
|
+
"home": "ホーム",
|
|
6
|
+
"projects": "プロジェクト",
|
|
7
|
+
"blog": "ブログ",
|
|
8
|
+
"navigation": "メインナビゲーション",
|
|
9
|
+
"menu": "メニュー",
|
|
10
|
+
"closeMenu": "メニューを閉じる"
|
|
11
|
+
},
|
|
12
|
+
"theme": {
|
|
13
|
+
"switchToLight": "ライトテーマに切り替える",
|
|
14
|
+
"switchToDark": "ダークテーマに切り替える"
|
|
15
|
+
},
|
|
16
|
+
"locale": {
|
|
17
|
+
"switchLabel": "言語"
|
|
18
|
+
},
|
|
19
|
+
"projects": {
|
|
20
|
+
"cc": {
|
|
21
|
+
"name": "Content Collector",
|
|
22
|
+
"description": "RSS、YouTube、Redditの自動収集 + AI要約"
|
|
23
|
+
},
|
|
24
|
+
"pkm": {
|
|
25
|
+
"name": "PKM",
|
|
26
|
+
"description": "個人ナレッジ管理 — ドキュメント解析、埋め込み、セマンティック検索"
|
|
27
|
+
},
|
|
28
|
+
"naeilUi": {
|
|
29
|
+
"name": "naeil-ui",
|
|
30
|
+
"description": "ミニマルデザインシステム — OKLCHトークン、Tailwind v4、shadcn"
|
|
31
|
+
},
|
|
32
|
+
"sa": {
|
|
33
|
+
"name": "Sustainability Analyzer",
|
|
34
|
+
"description": "ESGレポートAI分析 — PDF解析、定性評価、比較表の自動生成"
|
|
35
|
+
},
|
|
36
|
+
"babyAgent": {
|
|
37
|
+
"name": "Baby Agent",
|
|
38
|
+
"description": "育児AIエージェント — LINE Q&A、記録、リマインダー"
|
|
39
|
+
},
|
|
40
|
+
"status": {
|
|
41
|
+
"active": "アクティブ",
|
|
42
|
+
"coming": "準備中"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"account": {
|
|
47
|
+
"menu": "アカウントメニュー",
|
|
48
|
+
"account": "アカウント",
|
|
49
|
+
"login": "ログイン",
|
|
50
|
+
"logout": "ログアウト",
|
|
51
|
+
"busy": "ログアウト中…"
|
|
52
|
+
},
|
|
53
|
+
"footer": {
|
|
54
|
+
"navigation": "ナビゲーション",
|
|
55
|
+
"projects": "プロジェクト",
|
|
56
|
+
"blog": "ブログ",
|
|
57
|
+
"social": "ソーシャル",
|
|
58
|
+
"description": "Tomorrow starts here."
|
|
59
|
+
},
|
|
60
|
+
"locale": {
|
|
61
|
+
"names": {
|
|
62
|
+
"en": "English",
|
|
63
|
+
"ko": "한국어",
|
|
64
|
+
"ja": "日本語"
|
|
65
|
+
},
|
|
66
|
+
"pending": "言語を変更しています…",
|
|
67
|
+
"failed": "言語を変更できませんでした。作業内容は保持されています。",
|
|
68
|
+
"retry": "再試行",
|
|
69
|
+
"errors": {
|
|
70
|
+
"badRequest": "このアドレスは無効です。",
|
|
71
|
+
"notFound": "ページが見つかりません。",
|
|
72
|
+
"unauthenticated": "続けるにはログインしてください。",
|
|
73
|
+
"forbidden": "このページへのアクセス権限がありません。",
|
|
74
|
+
"unavailable": "サービスを一時的に利用できません。もう一度お試しください。"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"naeil": {
|
|
3
|
+
"header": {
|
|
4
|
+
"nav": {
|
|
5
|
+
"home": "홈",
|
|
6
|
+
"projects": "프로젝트",
|
|
7
|
+
"blog": "블로그",
|
|
8
|
+
"navigation": "주요 메뉴",
|
|
9
|
+
"menu": "메뉴",
|
|
10
|
+
"closeMenu": "메뉴 닫기"
|
|
11
|
+
},
|
|
12
|
+
"theme": {
|
|
13
|
+
"switchToLight": "밝은 테마로 전환",
|
|
14
|
+
"switchToDark": "어두운 테마로 전환"
|
|
15
|
+
},
|
|
16
|
+
"locale": {
|
|
17
|
+
"switchLabel": "언어"
|
|
18
|
+
},
|
|
19
|
+
"projects": {
|
|
20
|
+
"cc": {
|
|
21
|
+
"name": "Content Collector",
|
|
22
|
+
"description": "RSS, YouTube, Reddit 자동 수집 + AI 요약"
|
|
23
|
+
},
|
|
24
|
+
"pkm": {
|
|
25
|
+
"name": "PKM",
|
|
26
|
+
"description": "개인 지식 관리 — 문서 파싱, 임베딩, 시맨틱 검색"
|
|
27
|
+
},
|
|
28
|
+
"naeilUi": {
|
|
29
|
+
"name": "naeil-ui",
|
|
30
|
+
"description": "미니멀 디자인 시스템 — OKLCH 토큰, Tailwind v4, shadcn"
|
|
31
|
+
},
|
|
32
|
+
"sa": {
|
|
33
|
+
"name": "Sustainability Analyzer",
|
|
34
|
+
"description": "ESG 리포트 AI 분석 — PDF 파싱, 정성평가, 비교표 자동 생성"
|
|
35
|
+
},
|
|
36
|
+
"babyAgent": {
|
|
37
|
+
"name": "Baby Agent",
|
|
38
|
+
"description": "육아 AI 에이전트 — LINE 기반 Q&A, 기록, 리마인더"
|
|
39
|
+
},
|
|
40
|
+
"status": {
|
|
41
|
+
"active": "활성",
|
|
42
|
+
"coming": "준비 중"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"account": {
|
|
47
|
+
"menu": "계정 메뉴",
|
|
48
|
+
"account": "계정",
|
|
49
|
+
"login": "로그인",
|
|
50
|
+
"logout": "로그아웃",
|
|
51
|
+
"busy": "로그아웃 중…"
|
|
52
|
+
},
|
|
53
|
+
"footer": {
|
|
54
|
+
"navigation": "네비게이션",
|
|
55
|
+
"projects": "프로젝트",
|
|
56
|
+
"blog": "블로그",
|
|
57
|
+
"social": "소셜",
|
|
58
|
+
"description": "Tomorrow starts here."
|
|
59
|
+
},
|
|
60
|
+
"locale": {
|
|
61
|
+
"names": {
|
|
62
|
+
"en": "English",
|
|
63
|
+
"ko": "한국어",
|
|
64
|
+
"ja": "日本語"
|
|
65
|
+
},
|
|
66
|
+
"pending": "언어를 변경하는 중…",
|
|
67
|
+
"failed": "언어를 변경하지 못했습니다. 작업 내용은 유지됩니다.",
|
|
68
|
+
"retry": "다시 시도",
|
|
69
|
+
"errors": {
|
|
70
|
+
"badRequest": "올바르지 않은 주소입니다.",
|
|
71
|
+
"notFound": "페이지를 찾을 수 없습니다.",
|
|
72
|
+
"unauthenticated": "계속하려면 로그인하세요.",
|
|
73
|
+
"forbidden": "이 페이지에 접근할 권한이 없습니다.",
|
|
74
|
+
"unavailable": "일시적으로 서비스를 이용할 수 없습니다. 다시 시도하세요."
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Owned-service language runtime
|
|
2
|
+
|
|
3
|
+
The opt-in `@naeil/ui/naeil-locale` entries support the registered naeil Next applications. English uses `/`, Korean `/ko`, and Japanese `/ja`, including deep routes. The URL determines the language. Cookie and browser preferences never redirect or overwrite it. The existing public `i18n/routing`, `Nav` and `Footer` APIs retain their previous behavior.
|
|
4
|
+
|
|
5
|
+
Use exact `next-intl@4.14.8` with the shared server/client entries. Next and React remain external peers. Standalone header/footer imports do not require Next or next-intl.
|
|
6
|
+
|
|
7
|
+
## Entries and ownership
|
|
8
|
+
|
|
9
|
+
| Import | Responsibility |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `@naeil/ui/naeil-locale` | Supported locales, strict service/route registry, `localePath`, `localeHref`, legacy receiving aliases and logical-route comparison |
|
|
12
|
+
| `/naeil-locale/server` | `createNaeilLocaleProxy`, `createNaeilRequestConfig`, request access markers and `localeMetadata` |
|
|
13
|
+
| `/naeil-locale/client` | Root `NaeilLocaleController`, locale `NaeilLocaleProvider`, `useLocaleController`, `useLocaleBeforeUnload` |
|
|
14
|
+
| `/naeil-locale/messages` | Selected common/application JSON loading and namespace merge |
|
|
15
|
+
| `/naeil-locale/checker` | Three-language key, nonempty value, ICU syntax and argument compatibility checks |
|
|
16
|
+
| `/naeil-locale/chrome` | Existing header/account/footer presentation using the provider's selected common dictionary |
|
|
17
|
+
|
|
18
|
+
Place the controller and app-owned session/business store in `app/layout.tsx`, above `[locale]`. Place the shared provider in `app/[locale]/layout.tsx` using the validated locale and server-loaded messages. Keep raw input, dialogs, undo, save/run controllers, stream readers and document-departure guards in the root lifetime. Locale remounts must not save, abort, reset, or seed a retained draft from older server props. Translate message keys at the rendering boundary, not inside persistent business state.
|
|
19
|
+
|
|
20
|
+
The shared config sets `localePrefix: "as-needed"`, `localeDetection: false`, `localeCookie: false`, and `alternateLinks: false`. Consumers set Next's `skipProxyUrlNormalize: true` and `skipTrailingSlashRedirect: true`; normalization follows the existing protocol/auth checks. A trusted ingress consumer may pass `requestOrigin: request => existingValidatedRequestUrl(request).origin` to the proxy. This keeps alias redirects and internal rewrites on the validated authority, including local127.0.0.1 deployments. Never derive it from an unvalidated forwarded host.
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
// app/layout.tsx — inside the existing html/body
|
|
24
|
+
<NaeilLocaleController service="estimate" preferenceWritesEnabled={false}>
|
|
25
|
+
<BusinessStateProvider>{children}</BusinessStateProvider>
|
|
26
|
+
</NaeilLocaleController>
|
|
27
|
+
|
|
28
|
+
// app/[locale]/layout.tsx — validate locale and setRequestLocale on the server
|
|
29
|
+
<NaeilLocaleProvider locale={locale} messages={await getMessages()}>
|
|
30
|
+
{children}
|
|
31
|
+
</NaeilLocaleProvider>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use `createNaeilRequestConfig({namespace: "estimate", messages: {en: () => import("../../messages/en.json"), ko: () => import("../../messages/ko.json"), ja: () => import("../../messages/ja.json")}})` in the next-intl request config. Every app JSON has exactly its own namespace. The package owns `naeil`; do not copy it into an app. The shared checker is a required build gate. The loader imports only the selected app dictionary and shared dictionary; an observable English recovery handles unexpected runtime omissions. Such omissions still fail acceptance.
|
|
35
|
+
|
|
36
|
+
Render complete paths with `localePath` for same-service navigation and `localeHref` for owned service links. Pass those paths to base Next Link/router or anchors without another locale option. The controller performs `router.replace(href, {scroll: false})`, serializes requests and waits for the matching provider arrival. It restores a stable `data-naeil-focus-id`, input `name`, or `id`. Only a successful explicit selection may write preference; history, prefetch and direct visits do not. Storage failure cannot block a path change.
|
|
37
|
+
|
|
38
|
+
The canonical chrome can be imported from `/naeil-locale/chrome` under the shared provider. Existing `/naeil-header` and `/naeil-footer` remain standalone compatibility adapters and include the small three-language common dictionary. Consumer Link, auth, save guards, frame overrides, desktop/mobile account locks and project data remain consumer-owned.
|
|
39
|
+
|
|
40
|
+
## Security and rollout
|
|
41
|
+
|
|
42
|
+
The proxy runs exact existing protocol boundaries first, strips external private markers, strictly classifies UI paths, applies the existing app authorizer, and then runs next-intl. Protected entries without an authorizer fail closed. A marker is only a rendering hint: every protected server data read must independently authorize. RSC denial renders a valid localized access boundary and retains the root draft; it must not send login HTML or redirect an in-progress editor to another document. Keep the root beforeunload guard active during RSC failure and access recovery.
|
|
43
|
+
|
|
44
|
+
`localePath` is not an auth-return validator. Keep existing exact return/invite/callback/relay origin and envelope validation. Protocol paths stay outside `[locale]`; localized protocol aliases are rejected. Public metadata advertises only available translations. Protected/auth/error UI is noindex without SEO alternates.
|
|
45
|
+
|
|
46
|
+
Receiver deployment and sending are separate gates. `preferenceWritesEnabled` defaults to false. Before first exposure, validate a separate receiver-compatible fallback or the previous build's safe rejection of new paths. After all required receiver and auth receipts pass, enable the reviewed cross-service links and explicit preference writes. Keep package, source, hosted Docs, app identities, activation times and rollback receipts separate. Home and Baby are outside this migration.
|
package/docs/package-release.md
CHANGED
|
@@ -31,6 +31,17 @@ pnpm exec playwright install chromium firefox webkit
|
|
|
31
31
|
pnpm test:browser
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
The chrome fixture server and standalone navigation sample use `NAEIL_UI_FIXTURE_PORT`, with the unchanged default defined in `scripts/chrome-fixture-config.ts` in the repository. The same module supplies every fixture URL. An explicit port also isolates generated fixtures, test results and HTML reports by port; leave it unset to retain the existing CI paths. Choose a free integer port from 1 to 65535.
|
|
35
|
+
|
|
36
|
+
For two concurrent fixture-only runs in one worktree, use separate terminals:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
NAEIL_UI_CHROME_ONLY=1 NAEIL_UI_FIXTURE_PORT=16081 pnpm test:browser e2e/page-frame.spec.ts --project=chromium
|
|
40
|
+
NAEIL_UI_CHROME_ONLY=1 NAEIL_UI_FIXTURE_PORT=16082 pnpm test:browser e2e/page-frame.spec.ts --project=chromium
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`NAEIL_UI_CHROME_ONLY=1` skips the unrelated Storybook server. Full suites still use `NAEIL_UI_STORYBOOK_PORT` for Storybook. Do not overlap an unset-port run (which cleans the default `test-results` directory) with custom-port runs in the same worktree. The standalone sample uses the same port setting: `NAEIL_UI_FIXTURE_PORT=16083 pnpm exec tsx scripts/serve-navigation-sample.ts`. Stop standalone previews after use; Playwright stops its own fixture server.
|
|
44
|
+
|
|
34
45
|
`check:package:boundary` inspects an actual `npm pack --ignore-scripts` archive for every declared export, runtime dependencies, source aliases, relative imports, required CSS/tokens/documents/notices and forbidden website payload. `check:consumers` separately installs that tarball with npm into two temporary directories. It builds the reusable React example with Vite/Tailwind, type-checks with library checks enabled, imports shared deep modules, checks SSR and CSS, and asserts Next/Supabase/Three are absent. A separate Next production build exercises root exports and the deep paths observed in the reachable Next consumer, with consumer-owned messages and no auth backend. Neither fixture uses repository dependency symlinks. Network access is needed for uncached npm dependencies; temporary installs are removed on completion or failure.
|
|
35
46
|
|
|
36
47
|
For a frozen release candidate, both archive-producing checks can enforce the reviewed SHA-256 before extraction or consumer installation:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naeil/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"sideEffects": [
|
|
@@ -145,12 +145,36 @@
|
|
|
145
145
|
"./release": {
|
|
146
146
|
"types": "./dist/lib/ui-release.d.ts",
|
|
147
147
|
"import": "./dist/lib/ui-release.js"
|
|
148
|
+
},
|
|
149
|
+
"./naeil-locale": {
|
|
150
|
+
"types": "./dist/naeil-locale/index.d.ts",
|
|
151
|
+
"import": "./dist/naeil-locale/index.js"
|
|
152
|
+
},
|
|
153
|
+
"./naeil-locale/client": {
|
|
154
|
+
"types": "./dist/naeil-locale/client.d.ts",
|
|
155
|
+
"import": "./dist/naeil-locale/client.js"
|
|
156
|
+
},
|
|
157
|
+
"./naeil-locale/server": {
|
|
158
|
+
"types": "./dist/naeil-locale/server.d.ts",
|
|
159
|
+
"import": "./dist/naeil-locale/server.js"
|
|
160
|
+
},
|
|
161
|
+
"./naeil-locale/messages": {
|
|
162
|
+
"types": "./dist/naeil-locale/messages.d.ts",
|
|
163
|
+
"import": "./dist/naeil-locale/messages.js"
|
|
164
|
+
},
|
|
165
|
+
"./naeil-locale/checker": {
|
|
166
|
+
"types": "./dist/naeil-locale/checker.d.ts",
|
|
167
|
+
"import": "./dist/naeil-locale/checker.js"
|
|
168
|
+
},
|
|
169
|
+
"./naeil-locale/chrome": {
|
|
170
|
+
"types": "./dist/naeil-locale/chrome.d.ts",
|
|
171
|
+
"import": "./dist/naeil-locale/chrome.js"
|
|
148
172
|
}
|
|
149
173
|
},
|
|
150
174
|
"scripts": {
|
|
151
175
|
"dev": "next dev",
|
|
152
176
|
"build": "next build",
|
|
153
|
-
"build:pkg": "pnpm build:release && pnpm check:brand && tsup && tsup --config tsup.deep.config.ts && tsx scripts/fix-deep-imports.ts && pnpm build:tokens && node scripts/build-release-entry.mjs",
|
|
177
|
+
"build:pkg": "pnpm check:messages && pnpm build:release && pnpm check:brand && tsup && tsup --config tsup.deep.config.ts && tsup --config tsup.locale.config.ts && tsx scripts/copy-locale-json.ts && tsx scripts/fix-deep-imports.ts && pnpm build:tokens && node scripts/build-release-entry.mjs && pnpm check:locale:package",
|
|
154
178
|
"start": "next start",
|
|
155
179
|
"lint": "eslint",
|
|
156
180
|
"test": "vitest run",
|
|
@@ -168,11 +192,13 @@
|
|
|
168
192
|
"check:brand": "tsx scripts/build-brand.ts --check",
|
|
169
193
|
"build:release": "node scripts/build-ui-release.mjs",
|
|
170
194
|
"rollout": "node scripts/rollout/rollout.mjs",
|
|
171
|
-
"test:rollout": "node --test scripts/rollout/*.test.mjs scripts/verify-ui-production.test.mjs"
|
|
195
|
+
"test:rollout": "node --test scripts/rollout/*.test.mjs scripts/verify-ui-production.test.mjs",
|
|
196
|
+
"check:messages": "tsx scripts/check-locale-messages.ts",
|
|
197
|
+
"check:locale:package": "tsx scripts/check-locale-package.ts"
|
|
172
198
|
},
|
|
173
199
|
"peerDependencies": {
|
|
174
200
|
"next": "^15 || ^16",
|
|
175
|
-
"next-intl": "
|
|
201
|
+
"next-intl": "4.14.8",
|
|
176
202
|
"react": "^19",
|
|
177
203
|
"react-dom": "^19"
|
|
178
204
|
},
|
|
@@ -184,7 +210,9 @@
|
|
|
184
210
|
"radix-ui": "^1.4.3",
|
|
185
211
|
"sonner": "^2.0.7",
|
|
186
212
|
"tailwind-merge": "^3.5.0",
|
|
187
|
-
"tw-animate-css": "^1.4.0"
|
|
213
|
+
"tw-animate-css": "^1.4.0",
|
|
214
|
+
"@formatjs/icu-messageformat-parser": "3.5.1",
|
|
215
|
+
"server-only": "0.0.1"
|
|
188
216
|
},
|
|
189
217
|
"devDependencies": {
|
|
190
218
|
"@axe-core/playwright": "^4.13.0",
|
|
@@ -212,7 +240,7 @@
|
|
|
212
240
|
"eslint-config-prettier": "^10.1.8",
|
|
213
241
|
"gray-matter": "^4.0.3",
|
|
214
242
|
"next": "16.1.7",
|
|
215
|
-
"next-intl": "
|
|
243
|
+
"next-intl": "4.14.8",
|
|
216
244
|
"pretendard": "^1.3.9",
|
|
217
245
|
"prettier": "^3.8.1",
|
|
218
246
|
"react": "19.2.3",
|
|
File without changes
|