@korioinc/next-core 2.0.23 → 2.0.25
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/auth/routing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/auth/routing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqCxD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmB1F"}
|
package/dist/auth/routing.js
CHANGED
|
@@ -14,13 +14,16 @@ function isPathMatching(path, patterns) {
|
|
|
14
14
|
}
|
|
15
15
|
// 경로에서 locale 접두사를 제거하는 함수
|
|
16
16
|
function removeLocalePrefix(pathname) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
const pathMatch = pathname.match(/^\/([^\\/]+)(?:\/|$)/);
|
|
18
|
+
const localeSegment = pathMatch?.[1];
|
|
19
|
+
if (!localeSegment) {
|
|
20
|
+
return pathname;
|
|
21
|
+
}
|
|
22
|
+
const canonicalLocale = locales.find((locale) => locale.toLowerCase() === localeSegment.toLowerCase());
|
|
23
|
+
if (!canonicalLocale) {
|
|
24
|
+
return pathname;
|
|
22
25
|
}
|
|
23
|
-
return pathname;
|
|
26
|
+
return pathname.replace(new RegExp(`^/${canonicalLocale}(?=/|$)`, 'i'), '') || '/';
|
|
24
27
|
}
|
|
25
28
|
export async function handleAuthRouting(request) {
|
|
26
29
|
const config = getConfig();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/theme-switcher/index.tsx"],"names":[],"mappings":"AAuCA,QAAA,MAAM,aAAa,+
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/theme-switcher/index.tsx"],"names":[],"mappings":"AAuCA,QAAA,MAAM,aAAa,+CAsGlB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -20,8 +20,13 @@ const normalizeTheme = ({ theme, resolvedTheme, themeOrder, }) => {
|
|
|
20
20
|
const ThemeSwitcher = () => {
|
|
21
21
|
const { theme, resolvedTheme, setTheme, themes } = useTheme();
|
|
22
22
|
const [mounted, setMounted] = React.useState(false);
|
|
23
|
+
const [canAnimateColors, setCanAnimateColors] = React.useState(false);
|
|
23
24
|
React.useEffect(() => {
|
|
24
25
|
setMounted(true);
|
|
26
|
+
const rafId = window.requestAnimationFrame(() => {
|
|
27
|
+
setCanAnimateColors(true);
|
|
28
|
+
});
|
|
29
|
+
return () => window.cancelAnimationFrame(rafId);
|
|
25
30
|
}, []);
|
|
26
31
|
const themeOrder = getThemeOrder(themes);
|
|
27
32
|
const currentTheme = normalizeTheme({ theme, resolvedTheme, themeOrder });
|
|
@@ -35,6 +40,6 @@ const ThemeSwitcher = () => {
|
|
|
35
40
|
if (!mounted) {
|
|
36
41
|
return (_jsx("button", { className: 'border-glass-strong bg-glass relative inline-flex h-9 w-9 items-center justify-center rounded-md border opacity-0', "aria-hidden": 'true', children: _jsx("div", { className: 'h-5 w-5' }) }));
|
|
37
42
|
}
|
|
38
|
-
return (_jsxs("button", { onClick: toggleTheme, className:
|
|
43
|
+
return (_jsxs("button", { onClick: toggleTheme, className: `border-glass-strong bg-glass hover:bg-glass-tinted relative inline-flex h-9 w-9 items-center justify-center rounded-md border ${canAnimateColors ? 'transition-colors' : ''}`, "aria-label": `Switch theme (current: ${currentThemeLabel})`, title: `Theme: ${currentThemeLabel} (click to change)`, children: [_jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', className: `absolute h-5 w-5 transition-all ${currentTheme === 'light' ? 'scale-100 rotate-0 opacity-100' : 'scale-0 rotate-90 opacity-0'}`, children: [_jsx("circle", { cx: '12', cy: '12', r: '5' }), _jsx("line", { x1: '12', y1: '1', x2: '12', y2: '3' }), _jsx("line", { x1: '12', y1: '21', x2: '12', y2: '23' }), _jsx("line", { x1: '4.22', y1: '4.22', x2: '5.64', y2: '5.64' }), _jsx("line", { x1: '18.36', y1: '18.36', x2: '19.78', y2: '19.78' }), _jsx("line", { x1: '1', y1: '12', x2: '3', y2: '12' }), _jsx("line", { x1: '21', y1: '12', x2: '23', y2: '12' }), _jsx("line", { x1: '4.22', y1: '19.78', x2: '5.64', y2: '18.36' }), _jsx("line", { x1: '18.36', y1: '5.64', x2: '19.78', y2: '4.22' })] }), _jsx("svg", { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', className: `absolute h-5 w-5 transition-all ${currentTheme === 'dark' ? 'scale-100 rotate-0 opacity-100' : 'scale-0 -rotate-90 opacity-0'}`, children: _jsx("path", { d: 'M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z' }) }), _jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round', className: `absolute h-5 w-5 transition-all ${currentTheme === 'system' ? 'scale-100 rotate-0 opacity-100' : 'scale-0 rotate-90 opacity-0'}`, children: [_jsx("rect", { x: '3', y: '4', width: '18', height: '12', rx: '2' }), _jsx("line", { x1: '8', y1: '20', x2: '16', y2: '20' }), _jsx("line", { x1: '12', y1: '16', x2: '12', y2: '20' })] })] }));
|
|
39
44
|
};
|
|
40
45
|
export default ThemeSwitcher;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/i18n/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsC7D;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/i18n/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsC7D;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAiGD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,yBAsEvD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,OAAO,GAAG,MAAM,CAShE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW9F;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAoBvG;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UAY7E;AAsBD,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAY,0BAwB3D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK1D;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CAMvE;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU1D;AAED,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAIpF;AAED,KAAK,aAAa,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC7C,eAAe,GACf,uBAAuB,GACvB,SAAS,CAAC;AAiDd,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAErF;AAED,wBAAsB,UAAU,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAIxE;AAED,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,MAAM,CAAC,CAKnE"}
|
package/dist/i18n/routing.js
CHANGED
|
@@ -47,11 +47,25 @@ const setCookie = (response, locale) => {
|
|
|
47
47
|
});
|
|
48
48
|
return response;
|
|
49
49
|
};
|
|
50
|
+
const getCanonicalLocale = (locale) => {
|
|
51
|
+
if (!locale) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return locales.find((supportedLocale) => supportedLocale.toLowerCase() === locale.toLowerCase());
|
|
55
|
+
};
|
|
56
|
+
const getPathLocaleSegment = (pathname) => {
|
|
57
|
+
const pathMatch = pathname.match(/^\/([^\\/]+)(?:\/|$)/);
|
|
58
|
+
return pathMatch?.[1];
|
|
59
|
+
};
|
|
60
|
+
const replacePathLocale = (pathname, locale) => {
|
|
61
|
+
return pathname.replace(/^\/[^\\/]+(?=\/|$)/, `/${locale}`);
|
|
62
|
+
};
|
|
50
63
|
/**
|
|
51
64
|
* URL에서 locale 부분을 제거하는 헬퍼 함수
|
|
52
65
|
*/
|
|
53
66
|
const removeLocaleFromPath = (pathname, locale) => {
|
|
54
|
-
|
|
67
|
+
const localePattern = new RegExp(`^/${locale}(?=/|$)`, 'i');
|
|
68
|
+
return pathname.replace(localePattern, '') || '/';
|
|
55
69
|
};
|
|
56
70
|
/**
|
|
57
71
|
* URL에서 locale을 제거하고 리다이렉트하는 함수
|
|
@@ -67,6 +81,17 @@ const redirectWithoutLocale = (request, pathname, locale, shouldSetCookie = fals
|
|
|
67
81
|
}
|
|
68
82
|
return response;
|
|
69
83
|
};
|
|
84
|
+
const redirectWithLocale = (request, pathname, locale, shouldSetCookie = false) => {
|
|
85
|
+
const newPathname = replacePathLocale(pathname, locale);
|
|
86
|
+
const url = new URL(newPathname, request.url);
|
|
87
|
+
url.search = request.nextUrl.search;
|
|
88
|
+
url.hash = request.nextUrl.hash;
|
|
89
|
+
const response = setRoutingHeaders(NextResponse.redirect(url, 302), newPathname, request.nextUrl.search);
|
|
90
|
+
if (shouldSetCookie) {
|
|
91
|
+
setCookie(response, locale);
|
|
92
|
+
}
|
|
93
|
+
return response;
|
|
94
|
+
};
|
|
70
95
|
/**
|
|
71
96
|
* 내부적으로 locale을 처리하는 rewrite 함수
|
|
72
97
|
*/
|
|
@@ -79,24 +104,22 @@ const rewriteWithLocale = (request, pathname, locale) => {
|
|
|
79
104
|
};
|
|
80
105
|
export function handleLocaleRouting(request) {
|
|
81
106
|
const { pathname } = request.nextUrl;
|
|
82
|
-
const
|
|
83
|
-
const
|
|
107
|
+
const localeCookie = request.cookies.get(LOCALE_COOKIE_NAME);
|
|
108
|
+
const cookieLocale = getCanonicalLocale(localeCookie?.value);
|
|
84
109
|
const defaultFallback = DEFAULT_FALLBACK();
|
|
85
110
|
// 1. URL에서 locale 감지
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
pathLocale = locale;
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
});
|
|
111
|
+
const pathLocaleSegment = getPathLocaleSegment(pathname);
|
|
112
|
+
const pathLocale = getCanonicalLocale(pathLocaleSegment);
|
|
113
|
+
const pathnameHasLocale = pathLocale !== undefined;
|
|
94
114
|
// 2. URL에 locale이 포함된 경우
|
|
95
115
|
if (pathnameHasLocale) {
|
|
116
|
+
if (pathLocaleSegment !== pathLocale) {
|
|
117
|
+
return redirectWithLocale(request, pathname, pathLocale, cookieLocale !== pathLocale);
|
|
118
|
+
}
|
|
96
119
|
// 이미 path에 locale이 있을 때
|
|
97
120
|
const response = setRoutingHeaders(NextResponse.next(), pathname, request.nextUrl.search);
|
|
98
121
|
// 쿠키 값이 path locale과 다를 경우
|
|
99
|
-
if (
|
|
122
|
+
if (cookieLocale !== pathLocale) {
|
|
100
123
|
// 기본 locale인 경우 URL에서 제거
|
|
101
124
|
if (LOCALE_PREFIX === 'as-needed' && pathLocale === defaultFallback) {
|
|
102
125
|
return redirectWithoutLocale(request, pathname, pathLocale, true);
|
|
@@ -112,14 +135,14 @@ export function handleLocaleRouting(request) {
|
|
|
112
135
|
}
|
|
113
136
|
// 3. URL에 locale이 없는 경우
|
|
114
137
|
// 쿠키가 기본 locale이고, as-needed 설정일 때 내부적으로만 locale 처리
|
|
115
|
-
if (LOCALE_PREFIX === 'as-needed' &&
|
|
138
|
+
if (LOCALE_PREFIX === 'as-needed' && cookieLocale === defaultFallback) {
|
|
116
139
|
return rewriteWithLocale(request, pathname, defaultFallback);
|
|
117
140
|
}
|
|
118
141
|
// 4. 적절한 locale 감지 및 적용
|
|
119
142
|
const defaultLocale = getRequestLocale(request.headers);
|
|
120
143
|
let locale = getCookieLocale(request.headers, pathname) || defaultLocale;
|
|
121
|
-
const findLocale = match([locale], locales, defaultLocale);
|
|
122
|
-
if (locale !== findLocale) {
|
|
144
|
+
const findLocale = getCanonicalLocale(match([locale], locales, defaultLocale));
|
|
145
|
+
if (findLocale && locale !== findLocale) {
|
|
123
146
|
locale = findLocale;
|
|
124
147
|
}
|
|
125
148
|
// 기본 locale이고 as-needed 설정인 경우 URL에는 포함하지 않음
|
|
@@ -142,24 +165,17 @@ export function getRequestLocale(requestHeaders) {
|
|
|
142
165
|
headers: { 'accept-language': langHeader },
|
|
143
166
|
}).languages(locales.slice());
|
|
144
167
|
const activeLocale = languages[0] || DEFAULT_FALLBACK();
|
|
145
|
-
return activeLocale;
|
|
168
|
+
return getCanonicalLocale(activeLocale) || activeLocale;
|
|
146
169
|
}
|
|
147
170
|
export function getCookieLocale(requestHeaders, pathname) {
|
|
148
|
-
const cookieLocale = getCookieFromHeaders(requestHeaders, LOCALE_COOKIE_NAME);
|
|
171
|
+
const cookieLocale = getCanonicalLocale(getCookieFromHeaders(requestHeaders, LOCALE_COOKIE_NAME));
|
|
149
172
|
if (cookieLocale) {
|
|
150
173
|
return cookieLocale;
|
|
151
174
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const pathMatch = pathname.match(/^\/([^\\/]+)(?:\/|$)/);
|
|
155
|
-
if (pathMatch && pathMatch[1]) {
|
|
156
|
-
const potentialLocale = pathMatch[1];
|
|
157
|
-
if (Array.isArray(locales) && locales.includes(potentialLocale)) {
|
|
158
|
-
pathLocale = potentialLocale;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
175
|
+
if (!pathname) {
|
|
176
|
+
return undefined;
|
|
161
177
|
}
|
|
162
|
-
return
|
|
178
|
+
return getCanonicalLocale(getPathLocaleSegment(pathname));
|
|
163
179
|
}
|
|
164
180
|
export function getChangeLocalePath(pathname, currentLocale, nextLocale) {
|
|
165
181
|
// Create the new path based on whether the current path has a locale segment or not
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@korioinc/next-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./ads": {
|
|
@@ -79,7 +79,8 @@
|
|
|
79
79
|
"tsc-alias": "^1.8.16",
|
|
80
80
|
"tw-animate-css": "^1.4.0",
|
|
81
81
|
"typescript": "^5.9.3",
|
|
82
|
-
"
|
|
82
|
+
"vitest": "^4.0.18",
|
|
83
|
+
"@korioinc/next-configs": "2.0.25"
|
|
83
84
|
},
|
|
84
85
|
"dependencies": {
|
|
85
86
|
"@floating-ui/react": "^0.27.19",
|
|
@@ -94,7 +95,7 @@
|
|
|
94
95
|
"schema-dts": "^1.1.5",
|
|
95
96
|
"tailwind-merge": "^3.5.0",
|
|
96
97
|
"valtio": "^2.3.1",
|
|
97
|
-
"@korioinc/next-conf": "2.0.
|
|
98
|
+
"@korioinc/next-conf": "2.0.25"
|
|
98
99
|
},
|
|
99
100
|
"publishConfig": {
|
|
100
101
|
"access": "public",
|
|
@@ -119,6 +120,7 @@
|
|
|
119
120
|
"scripts": {
|
|
120
121
|
"build": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json && cp -r src/styles dist/ && cp -r src/types dist/",
|
|
121
122
|
"dev": "tsc -p tsconfig.json -w & tsc-alias -p tsconfig.json -w",
|
|
123
|
+
"test": "vitest run --config vitest.config.ts",
|
|
122
124
|
"lint": "eslint . --max-warnings 0",
|
|
123
125
|
"generate:component": "turbo gen react-component"
|
|
124
126
|
}
|