@korioinc/next-core 1.0.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/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/ads/components/AdContainer.d.ts +12 -0
- package/dist/ads/components/AdContainer.d.ts.map +1 -0
- package/dist/ads/components/AdContainer.js +287 -0
- package/dist/ads/components/GoogleAdSense.d.ts +6 -0
- package/dist/ads/components/GoogleAdSense.d.ts.map +1 -0
- package/dist/ads/components/GoogleAdSense.js +6 -0
- package/dist/ads/components/MockAdDisplay.d.ts +8 -0
- package/dist/ads/components/MockAdDisplay.d.ts.map +1 -0
- package/dist/ads/components/MockAdDisplay.js +13 -0
- package/dist/ads/config.d.ts +3 -0
- package/dist/ads/config.d.ts.map +1 -0
- package/dist/ads/config.js +134 -0
- package/dist/ads/index.d.ts +6 -0
- package/dist/ads/index.d.ts.map +1 -0
- package/dist/ads/index.js +7 -0
- package/dist/ads/types.d.ts +15 -0
- package/dist/ads/types.d.ts.map +1 -0
- package/dist/ads/types.js +1 -0
- package/dist/api-client/index.d.ts +31 -0
- package/dist/api-client/index.d.ts.map +1 -0
- package/dist/api-client/index.js +90 -0
- package/dist/auth/auth-manager.d.ts +45 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +75 -0
- package/dist/auth/index.client.d.ts +7 -0
- package/dist/auth/index.client.d.ts.map +1 -0
- package/dist/auth/index.client.js +5 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/index.server.d.ts +7 -0
- package/dist/auth/index.server.d.ts.map +1 -0
- package/dist/auth/index.server.js +5 -0
- package/dist/auth/providers/auth-context-provider.d.ts +21 -0
- package/dist/auth/providers/auth-context-provider.d.ts.map +1 -0
- package/dist/auth/providers/auth-context-provider.js +74 -0
- package/dist/auth/routing.d.ts +3 -0
- package/dist/auth/routing.d.ts.map +1 -0
- package/dist/auth/routing.js +40 -0
- package/dist/auth/types/auth.d.ts +23 -0
- package/dist/auth/types/auth.d.ts.map +1 -0
- package/dist/auth/types/auth.js +1 -0
- package/dist/auth/types/user.d.ts +6 -0
- package/dist/auth/types/user.d.ts.map +1 -0
- package/dist/auth/types/user.js +1 -0
- package/dist/auth/utils/auth.d.ts +32 -0
- package/dist/auth/utils/auth.d.ts.map +1 -0
- package/dist/auth/utils/auth.js +116 -0
- package/dist/auth/utils/permission.d.ts +29 -0
- package/dist/auth/utils/permission.d.ts.map +1 -0
- package/dist/auth/utils/permission.js +44 -0
- package/dist/components/head-manifest/index.d.ts +6 -0
- package/dist/components/head-manifest/index.d.ts.map +1 -0
- package/dist/components/head-manifest/index.js +4 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +7 -0
- package/dist/components/json-ld/index.d.ts +7 -0
- package/dist/components/json-ld/index.d.ts.map +1 -0
- package/dist/components/json-ld/index.js +6 -0
- package/dist/components/locale-switcher/_components/china-flag.d.ts +2 -0
- package/dist/components/locale-switcher/_components/china-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/china-flag.js +4 -0
- package/dist/components/locale-switcher/_components/japan-flag.d.ts +2 -0
- package/dist/components/locale-switcher/_components/japan-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/japan-flag.js +4 -0
- package/dist/components/locale-switcher/_components/korea-flag.d.ts +4 -0
- package/dist/components/locale-switcher/_components/korea-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/korea-flag.js +4 -0
- package/dist/components/locale-switcher/_components/taiwan-flag.d.ts +2 -0
- package/dist/components/locale-switcher/_components/taiwan-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/taiwan-flag.js +4 -0
- package/dist/components/locale-switcher/_components/usa-flag.d.ts +4 -0
- package/dist/components/locale-switcher/_components/usa-flag.d.ts.map +1 -0
- package/dist/components/locale-switcher/_components/usa-flag.js +4 -0
- package/dist/components/locale-switcher/index.d.ts +11 -0
- package/dist/components/locale-switcher/index.d.ts.map +1 -0
- package/dist/components/locale-switcher/index.js +69 -0
- package/dist/components/theme-switcher/index.d.ts +3 -0
- package/dist/components/theme-switcher/index.d.ts.map +1 -0
- package/dist/components/theme-switcher/index.js +20 -0
- package/dist/components/tooltip/index.d.ts +8 -0
- package/dist/components/tooltip/index.d.ts.map +1 -0
- package/dist/components/tooltip/index.js +40 -0
- package/dist/i18n/init-lingui.d.ts +7 -0
- package/dist/i18n/init-lingui.d.ts.map +1 -0
- package/dist/i18n/init-lingui.js +7 -0
- package/dist/i18n/lingui.setup.d.ts +15 -0
- package/dist/i18n/lingui.setup.d.ts.map +1 -0
- package/dist/i18n/lingui.setup.js +29 -0
- package/dist/i18n/providers/lingui-client-provider.d.ts +9 -0
- package/dist/i18n/providers/lingui-client-provider.d.ts.map +1 -0
- package/dist/i18n/providers/lingui-client-provider.js +14 -0
- package/dist/i18n/routing.d.ts +25 -0
- package/dist/i18n/routing.d.ts.map +1 -0
- package/dist/i18n/routing.js +252 -0
- package/dist/local-storage/index.d.ts +4 -0
- package/dist/local-storage/index.d.ts.map +1 -0
- package/dist/local-storage/index.js +4 -0
- package/dist/local-storage/local-storage-manager.d.ts +41 -0
- package/dist/local-storage/local-storage-manager.d.ts.map +1 -0
- package/dist/local-storage/local-storage-manager.js +200 -0
- package/dist/local-storage/valtio-persist.d.ts +31 -0
- package/dist/local-storage/valtio-persist.d.ts.map +1 -0
- package/dist/local-storage/valtio-persist.js +84 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +4 -0
- package/dist/navigation/permissions.d.ts +25 -0
- package/dist/navigation/permissions.d.ts.map +1 -0
- package/dist/navigation/permissions.js +97 -0
- package/dist/navigation/types.d.ts +57 -0
- package/dist/navigation/types.d.ts.map +1 -0
- package/dist/navigation/types.js +1 -0
- package/dist/navigation/utils.d.ts +42 -0
- package/dist/navigation/utils.d.ts.map +1 -0
- package/dist/navigation/utils.js +107 -0
- package/dist/utils/cookie.d.ts +3 -0
- package/dist/utils/cookie.d.ts.map +1 -0
- package/dist/utils/cookie.js +22 -0
- package/dist/utils/helpers.d.ts +5 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +18 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/sitemap.d.ts +13 -0
- package/dist/utils/sitemap.d.ts.map +1 -0
- package/dist/utils/sitemap.js +19 -0
- package/package.json +126 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { jwtVerify } from 'jose';
|
|
2
|
+
// JWT 시크릿 키
|
|
3
|
+
export const getJWTSecret = () => {
|
|
4
|
+
const secret = process.env.JWT_SECRET_KEY;
|
|
5
|
+
if (!secret) {
|
|
6
|
+
throw new Error('JWT_SECRET_KEY is not defined in environment variables');
|
|
7
|
+
}
|
|
8
|
+
return new TextEncoder().encode(secret);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* JWT 토큰 검증 및 페이로드 추출
|
|
12
|
+
*/
|
|
13
|
+
export async function verifyJWT(token) {
|
|
14
|
+
try {
|
|
15
|
+
const secret = getJWTSecret();
|
|
16
|
+
const { payload } = await jwtVerify(token, secret);
|
|
17
|
+
return payload;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
// Log error in development mode only
|
|
21
|
+
if (process.env.NODE_ENV === 'development') {
|
|
22
|
+
console.error('[Auth] JWT verification failed:', {
|
|
23
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
24
|
+
timestamp: new Date().toISOString(),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* JWT 페이로드에서 UserDto 객체 생성 (역할/권한 제외)
|
|
32
|
+
*/
|
|
33
|
+
export function createUserFromPayload(payload) {
|
|
34
|
+
if (!payload.props) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
// UserWithAuth에서 UserDto만 추출
|
|
38
|
+
const { roles, permissions, ...userDto } = payload.props;
|
|
39
|
+
return userDto;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 권한 목록 추출
|
|
43
|
+
*/
|
|
44
|
+
export function extractPermissions(payload) {
|
|
45
|
+
if (!payload.props) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
// 중복 제거
|
|
49
|
+
return [...new Set(payload.props.permissions || [])];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 토큰 만료 확인
|
|
53
|
+
*/
|
|
54
|
+
export function isTokenExpired(payload) {
|
|
55
|
+
return !!(payload.exp && payload.exp * 1000 < Date.now());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 클라이언트에서 JWT 디코드 (검증 없이)
|
|
59
|
+
*/
|
|
60
|
+
export function decodeJWT(token) {
|
|
61
|
+
try {
|
|
62
|
+
const parts = token.split('.');
|
|
63
|
+
if (parts.length !== 3) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const base64 = parts[1];
|
|
67
|
+
if (!base64) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
// Edge Runtime compatible base64 decoding
|
|
71
|
+
const base64url = base64.replace(/-/g, '+').replace(/_/g, '/');
|
|
72
|
+
const paddedBase64 = base64url + '=='.substring(0, (4 - (base64url.length % 4)) % 4);
|
|
73
|
+
// Use atob for Edge Runtime compatibility
|
|
74
|
+
const jsonString = atob(paddedBase64);
|
|
75
|
+
const payload = JSON.parse(jsonString);
|
|
76
|
+
return payload;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 페이로드로부터 인증 데이터를 생성하는 공통 함수
|
|
84
|
+
*/
|
|
85
|
+
function createAuthDataFromPayload(payload, token) {
|
|
86
|
+
if (!payload || isTokenExpired(payload)) {
|
|
87
|
+
return { user: null, roles: [], permissions: [], token: token };
|
|
88
|
+
}
|
|
89
|
+
const user = createUserFromPayload(payload);
|
|
90
|
+
if (!user) {
|
|
91
|
+
return { user: null, roles: [], permissions: [], token: token };
|
|
92
|
+
}
|
|
93
|
+
const permissions = extractPermissions(payload);
|
|
94
|
+
const roles = payload.props?.roles || [];
|
|
95
|
+
return { user, roles, permissions, token };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 클라이언트에서 토큰으로부터 인증 데이터를 생성하는 함수 (디코드만)
|
|
99
|
+
*/
|
|
100
|
+
export function createAuthDataFromTokenClient(token) {
|
|
101
|
+
if (!token) {
|
|
102
|
+
return { user: null, roles: [], permissions: [], token: null };
|
|
103
|
+
}
|
|
104
|
+
const payload = decodeJWT(token);
|
|
105
|
+
return createAuthDataFromPayload(payload, token);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 서버에서 토큰으로부터 인증 데이터를 생성하는 함수 (검증 포함)
|
|
109
|
+
*/
|
|
110
|
+
export async function createAuthDataFromTokenServer(token) {
|
|
111
|
+
if (!token) {
|
|
112
|
+
return { user: null, roles: [], permissions: [], token: null };
|
|
113
|
+
}
|
|
114
|
+
const payload = await verifyJWT(token);
|
|
115
|
+
return createAuthDataFromPayload(payload, token);
|
|
116
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AuthData } from '../../auth/types/auth';
|
|
2
|
+
import { Permission, Role } from '../../auth/types/user';
|
|
3
|
+
/**
|
|
4
|
+
* 특정 역할 확인 (순수 함수)
|
|
5
|
+
*/
|
|
6
|
+
export declare function checkHasRole(authData: AuthData, role: Role): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* 특정 권한 확인 (순수 함수)
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkHasPermission(authData: AuthData, permission: Permission): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 여러 권한 중 하나라도 있는지 확인 (순수 함수)
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkHasAnyPermission(authData: AuthData, requiredPermissions: Permission[]): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* 모든 권한을 가지고 있는지 확인 (순수 함수)
|
|
17
|
+
*/
|
|
18
|
+
export declare function checkHasAllPermissions(authData: AuthData, requiredPermissions: Permission[]): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* 특정 역할 또는 권한을 가지고 있는지 확인 (순수 함수)
|
|
21
|
+
* Role과 Permission을 하나의 인자로 받음
|
|
22
|
+
*/
|
|
23
|
+
export declare function checkHasRoleOrPermission(authData: AuthData, roleOrPermission: Role | Permission): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* 여러 역할 또는 권한 중 하나라도 있는지 확인 (순수 함수)
|
|
26
|
+
* Role과 Permission을 하나의 배열로 받음
|
|
27
|
+
*/
|
|
28
|
+
export declare function checkHasAnyRoleOrPermission(authData: AuthData, rolesOrPermissions: Array<Role | Permission>): boolean;
|
|
29
|
+
//# sourceMappingURL=permission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../../../src/auth/utils/permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAEzD;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAEpE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAEtF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,mBAAmB,EAAE,UAAU,EAAE,GAAG,OAAO,CAEpG;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,EAAE,mBAAmB,EAAE,UAAU,EAAE,GAAG,OAAO,CAErG;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,IAAI,GAAG,UAAU,GAAG,OAAO,CAMzG;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,EAAE,KAAK,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,OAAO,CAMrH"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 특정 역할 확인 (순수 함수)
|
|
3
|
+
*/
|
|
4
|
+
export function checkHasRole(authData, role) {
|
|
5
|
+
return authData.roles.includes(role);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 특정 권한 확인 (순수 함수)
|
|
9
|
+
*/
|
|
10
|
+
export function checkHasPermission(authData, permission) {
|
|
11
|
+
return authData.permissions.includes(permission);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 여러 권한 중 하나라도 있는지 확인 (순수 함수)
|
|
15
|
+
*/
|
|
16
|
+
export function checkHasAnyPermission(authData, requiredPermissions) {
|
|
17
|
+
return requiredPermissions.some((p) => authData.permissions.includes(p));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 모든 권한을 가지고 있는지 확인 (순수 함수)
|
|
21
|
+
*/
|
|
22
|
+
export function checkHasAllPermissions(authData, requiredPermissions) {
|
|
23
|
+
return requiredPermissions.every((p) => authData.permissions.includes(p));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 특정 역할 또는 권한을 가지고 있는지 확인 (순수 함수)
|
|
27
|
+
* Role과 Permission을 하나의 인자로 받음
|
|
28
|
+
*/
|
|
29
|
+
export function checkHasRoleOrPermission(authData, roleOrPermission) {
|
|
30
|
+
// Type-safe checking without casting
|
|
31
|
+
const isRole = authData.roles.includes(roleOrPermission);
|
|
32
|
+
const isPermission = authData.permissions.includes(roleOrPermission);
|
|
33
|
+
return isRole || isPermission;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 여러 역할 또는 권한 중 하나라도 있는지 확인 (순수 함수)
|
|
37
|
+
* Role과 Permission을 하나의 배열로 받음
|
|
38
|
+
*/
|
|
39
|
+
export function checkHasAnyRoleOrPermission(authData, rolesOrPermissions) {
|
|
40
|
+
if (rolesOrPermissions.length === 0) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return rolesOrPermissions.some((item) => checkHasRoleOrPermission(authData, item));
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/head-manifest/index.tsx"],"names":[],"mappings":"AAAA,UAAU,SAAS;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,2CAMjD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as LocaleSwitcher } from './locale-switcher';
|
|
2
|
+
export { default as ThemeSwitcher } from './theme-switcher';
|
|
3
|
+
export { default as Tooltip } from './tooltip';
|
|
4
|
+
export { HeadManifest } from './head-manifest';
|
|
5
|
+
export { JsonLd } from './json-ld';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAC;AAG/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// UI Components
|
|
2
|
+
export { default as LocaleSwitcher } from './locale-switcher';
|
|
3
|
+
export { default as ThemeSwitcher } from './theme-switcher';
|
|
4
|
+
export { default as Tooltip } from './tooltip';
|
|
5
|
+
// SEO Components
|
|
6
|
+
export { HeadManifest } from './head-manifest';
|
|
7
|
+
export { JsonLd } from './json-ld';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Thing, WithContext } from 'schema-dts';
|
|
2
|
+
interface JsonLdProps<T extends Thing> {
|
|
3
|
+
schema: WithContext<T>;
|
|
4
|
+
}
|
|
5
|
+
export declare function JsonLd<T extends Thing>({ schema }: JsonLdProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/json-ld/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD,UAAU,WAAW,CAAC,CAAC,SAAS,KAAK;IACnC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CACxB;AAED,wBAAgB,MAAM,CAAC,CAAC,SAAS,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,2CASjE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"china-flag.d.ts","sourceRoot":"","sources":["../../../../src/components/locale-switcher/_components/china-flag.tsx"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,SAAS,4CAyBhC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export default function ChinaFlag() {
|
|
3
|
+
return (_jsxs("svg", { className: 'h-5 w-5', viewBox: '0 0 640 480', xmlns: 'http://www.w3.org/2000/svg', children: [_jsx("rect", { fill: '#de2910', width: '640', height: '480' }), _jsxs("g", { fill: '#ffde00', children: [_jsx("polygon", { points: '192,96 206.1,145.5 256,116.5 215.4,145.5 229.5,195 192,166 154.5,195 168.6,145.5 128,116.5 177.9,145.5' }), _jsx("polygon", { points: '288,48 293.3,62.4 308.5,58.4 296.8,70.8 302.1,85.2 288,73.5 273.9,85.2 279.2,70.8 267.5,58.4 282.7,62.4', transform: 'rotate(23.036 256 0)' }), _jsx("polygon", { points: '352,96 357.3,110.4 372.5,106.4 360.8,118.8 366.1,133.2 352,121.5 337.9,133.2 343.2,118.8 331.5,106.4 346.7,110.4', transform: 'rotate(45.870 320 64)' }), _jsx("polygon", { points: '352,192 357.3,206.4 372.5,202.4 360.8,214.8 366.1,229.2 352,217.5 337.9,229.2 343.2,214.8 331.5,202.4 346.7,206.4', transform: 'rotate(69.945 320 208)' }), _jsx("polygon", { points: '288,240 293.3,254.4 308.5,250.4 296.8,262.8 302.1,277.2 288,265.5 273.9,277.2 279.2,262.8 267.5,250.4 282.7,254.4', transform: 'rotate(20.660 256 416)' })] })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"japan-flag.d.ts","sourceRoot":"","sources":["../../../../src/components/locale-switcher/_components/japan-flag.tsx"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,SAAS,4CAOhC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export default function JapanFlag() {
|
|
3
|
+
return (_jsxs("svg", { className: 'h-5 w-5', viewBox: '0 0 640 480', xmlns: 'http://www.w3.org/2000/svg', children: [_jsx("rect", { fill: '#fff', width: '640', height: '480' }), _jsx("circle", { fill: '#bc002d', cx: '320', cy: '240', r: '96' })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"korea-flag.d.ts","sourceRoot":"","sources":["../../../../src/components/locale-switcher/_components/korea-flag.tsx"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,SAAoB,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAiCjF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export default function KoreaFlag({ className = 'size-5' }) {
|
|
3
|
+
return (_jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 90 90', className: className, children: [_jsx("circle", { cx: '45', cy: '45', r: '45', fill: '#f3f4f5' }), _jsx("path", { d: 'M62.345 44.996c0 9.581-7.685 17.347-17.165 17.347s-17.165-7.766-17.165-17.347S35.7 27.649 45.18 27.649s17.165 7.766 17.165 17.347z', fill: '#c70000' }), _jsx("path", { d: 'M28.265 41.939c.543 4.369 1.335 9.238 8.059 9.743 2.52.151 7.423-.6 9.106-7.467 2.208-6.597 8.86-8.494 13.386-4.917 2.566 1.674 3.276 4.333 3.46 6.329-.205 6.41-3.885 11.958-8.605 14.433-5.427 3.226-12.946 3.293-19.533-1.594-2.968-2.786-7.116-7.92-5.873-16.527z', fill: '#3d5897' }), _jsxs("g", { fill: '#000', children: [_jsx("path", { d: 'M10.065 28.912l9.886-11.435 2.342 2.025-9.886 11.435z' }), _jsx("path", { d: 'M13.303 31.711l9.886-11.435 2.342 2.025-9.886 11.435z' }), _jsx("path", { d: 'M16.61 34.57l9.886-11.435 2.342 2.025-9.886 11.435z' }), _jsx("path", { d: 'M66.935 20.251l9.808 11.502-2.356 2.009-9.808-11.502z' }), _jsx("path", { d: 'M18.938 53.403l9.808 11.502-2.356 2.009-9.808-11.502zM12.356 59.016l9.808 11.502-2.356 2.009L10 61.025z' }), _jsx("polygon", { points: '19.61,60.79 15.68,56.18 13.33,58.19 17.27,62.81' }), _jsx("polygon", { points: '21.39,62.88 19.09,64.95 23.13,69.69 25.49,67.68' }), _jsx("polygon", { points: '72.87,62.45 76.67,57.93 74.34,55.99 70.58,60.48' }), _jsx("polygon", { points: '68.77,62.63 64.84,67.32 67.17,69.25 71.11,64.56' }), _jsx("polygon", { points: '65.49,59.88 61.55,64.58 63.88,66.52 67.83,61.81' }), _jsx("polygon", { points: '69.68,59.61 73.38,55.19 71.05,53.26 67.38,57.63' }), _jsx("polygon", { points: '72,65.3 68.06,70 70.39,71.93 74.34,67.22' }), _jsx("polygon", { points: '76.05,65.18 79.89,60.61 77.56,58.67 73.75,63.21' }), _jsx("polygon", { points: '75.83,24.09 73.53,26.16 77.64,30.98 80,28.98' }), _jsx("polygon", { points: '74.11,22.06 70.19,17.47 67.84,19.48 71.76,24.09' }), _jsx("polygon", { points: '65.25,29.71 67.56,27.72 63.61,23.09 61.25,25.1 65.29,29.83' }), _jsx("polygon", { points: '67.09,31.94 71.06,36.6 73.42,34.59 69.4,29.87' })] })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taiwan-flag.d.ts","sourceRoot":"","sources":["../../../../src/components/locale-switcher/_components/taiwan-flag.tsx"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,UAAU,4CAYjC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export default function TaiwanFlag() {
|
|
3
|
+
return (_jsxs("svg", { className: 'h-5 w-5', viewBox: '0 0 640 480', xmlns: 'http://www.w3.org/2000/svg', children: [_jsx("rect", { fill: '#fe0000', width: '640', height: '480' }), _jsx("rect", { fill: '#000095', width: '320', height: '240' }), _jsxs("g", { fill: '#fff', children: [_jsx("polygon", { points: '160,60 171.3,94.2 208,70.7 178.3,94.2 189.6,128.4 160,104.9 130.4,128.4 141.7,94.2 112,70.7 148.7,94.2' }), _jsx("circle", { fill: '#000095', cx: '160', cy: '120', r: '48' }), _jsx("circle", { fill: '#fff', cx: '160', cy: '120', r: '40' })] })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usa-flag.d.ts","sourceRoot":"","sources":["../../../../src/components/locale-switcher/_components/usa-flag.tsx"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,SAAoB,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAsC/E"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export default function UsaFlag({ className = 'size-5' }) {
|
|
3
|
+
return (_jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 90 90', className: className, children: [_jsx("path", { d: 'M0.511 51.794c.924 6.099 3.076 11.793 6.19 16.83h76.599c3.114-5.037 5.266-10.731 6.19-16.83H.511z', fill: '#f3f4f5' }), _jsx("path", { d: 'M69.638 82.649H20.362C27.441 87.291 35.902 90 45 90s17.559-2.709 24.638-7.351z', fill: '#f3f4f5' }), _jsx("path", { d: 'M49.629 37.768h39.785c-.988-6.111-3.209-11.806-6.395-16.83H49.629v16.83z', fill: '#f3f4f5' }), _jsx("path", { d: 'M49.629.24v6.673h19.326C63.248 3.316 56.681.963 49.629.24z', fill: '#f3f4f5' }), _jsx("path", { d: 'M6.701 68.624c3.472 5.617 8.146 10.408 13.661 14.025h49.276c5.516-3.617 10.189-8.408 13.661-14.025H6.701z', fill: '#dc3027' }), _jsx("path", { d: 'M89.414 37.768H49.629v14.025h39.86c.336-2.215.511-4.484.511-6.793 0-2.463-.206-4.876-.586-7.232z', fill: '#dc3027' }), _jsx("path", { d: 'M49.629 20.938h33.389c-3.587-5.656-8.397-10.454-14.064-14.025H49.629v14.025z', fill: '#dc3027' }), _jsx("path", { d: 'M49.629.236C48.107.08 46.563 0 45 0 20.147 0 0 20.147 0 45c0 2.309.175 4.578.511 6.794h49.118V.236z', fill: '#283991' }), _jsxs("g", { fill: '#f3f4f5', children: [_jsx("polygon", { points: '7.81,40.43 6.42,44.7 10.05,42.06 13.69,44.7 12.3,40.43 15.92,37.79 11.44,37.79 10.05,33.53 8.66,37.79 4.18,37.79' }), _jsx("polygon", { points: '33.21,40.43 31.82,44.7 35.45,42.06 39.09,44.7 37.7,40.43 41.32,37.79 36.84,37.79 35.45,33.53 34.07,37.79 29.58,37.79' }), _jsx("polygon", { points: '33.21,18.82 31.82,23.09 35.45,20.45 39.09,23.09 37.7,18.82 41.32,16.18 36.84,16.18 35.45,11.93 34.07,16.18 29.58,16.18' }), _jsx("polygon", { points: '20.48,29.62 19.09,33.9 22.73,31.26 26.36,33.9 24.97,29.62 28.6,26.99 24.11,26.99 22.73,22.73 21.34,26.99 16.86,26.99' })] })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface LocaleSwitcherProps {
|
|
2
|
+
/**
|
|
3
|
+
* Array of language codes to display in the switcher.
|
|
4
|
+
* Example: ['en', 'ko', 'jp']
|
|
5
|
+
* If not provided, defaults to all supported languages.
|
|
6
|
+
*/
|
|
7
|
+
languages?: string[];
|
|
8
|
+
}
|
|
9
|
+
export default function LocaleSwitcher({ languages }?: LocaleSwitcherProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/locale-switcher/index.tsx"],"names":[],"mappings":"AAoDA,UAAU,mBAAmB;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EAAE,SAAS,EAAE,GAAE,mBAAwB,kDA4E7E"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, useEffect, useState } from 'react';
|
|
4
|
+
import { usePathname, useRouter } from 'next/navigation';
|
|
5
|
+
import { getChangeLocalePath } from '../../i18n/routing';
|
|
6
|
+
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react';
|
|
7
|
+
import { useLingui } from '@lingui/react';
|
|
8
|
+
import ChinaFlag from './_components/china-flag';
|
|
9
|
+
import JapanFlag from './_components/japan-flag';
|
|
10
|
+
import KoreaFlag from './_components/korea-flag';
|
|
11
|
+
import TaiwanFlag from './_components/taiwan-flag';
|
|
12
|
+
import UsaFlag from './_components/usa-flag';
|
|
13
|
+
// All available languages
|
|
14
|
+
const allLanguages = [
|
|
15
|
+
{
|
|
16
|
+
code: 'en',
|
|
17
|
+
name: 'English',
|
|
18
|
+
flag: _jsx(UsaFlag, {}),
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
code: 'ko',
|
|
22
|
+
name: '한국어',
|
|
23
|
+
flag: _jsx(KoreaFlag, {}),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
code: 'jp',
|
|
27
|
+
name: '日本語',
|
|
28
|
+
flag: _jsx(JapanFlag, {}),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
code: 'zh-cn',
|
|
32
|
+
name: '简体中文',
|
|
33
|
+
flag: _jsx(ChinaFlag, {}),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
code: 'zh-tw',
|
|
37
|
+
name: '繁體中文',
|
|
38
|
+
flag: _jsx(TaiwanFlag, {}),
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
export default function LocaleSwitcher({ languages } = {}) {
|
|
42
|
+
const router = useRouter();
|
|
43
|
+
const pathname = usePathname();
|
|
44
|
+
const { i18n } = useLingui();
|
|
45
|
+
const [mounted, setMounted] = useState(false);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
setMounted(true);
|
|
48
|
+
}, []);
|
|
49
|
+
// Filter languages based on provided codes or use all
|
|
50
|
+
const availableLanguages = languages ? allLanguages.filter((lang) => languages.includes(lang.code)) : allLanguages;
|
|
51
|
+
// Get current locale from Lingui
|
|
52
|
+
const currentLocale = i18n.locale;
|
|
53
|
+
// Always provide a fallback to ensure currentLanguage is never undefined
|
|
54
|
+
const foundLanguage = availableLanguages.find((lang) => lang.code === currentLocale);
|
|
55
|
+
const currentLanguage = foundLanguage || availableLanguages[0];
|
|
56
|
+
const changeLanguage = (nextLocale) => {
|
|
57
|
+
const currentLocale = i18n.locale;
|
|
58
|
+
const newPath = getChangeLocalePath(pathname, currentLocale, nextLocale);
|
|
59
|
+
router.replace(newPath);
|
|
60
|
+
router.refresh();
|
|
61
|
+
};
|
|
62
|
+
if (!mounted) {
|
|
63
|
+
return (_jsx("div", { className: 'border-input bg-card relative inline-flex h-9 w-9 items-center justify-center rounded-md border opacity-0', children: _jsx("div", { className: 'h-5 w-5' }) }));
|
|
64
|
+
}
|
|
65
|
+
if (!currentLanguage) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return (_jsxs(Menu, { as: 'div', className: 'relative', children: [_jsx(MenuButton, { className: 'border-input bg-card hover:bg-accent hover:text-accent-foreground relative inline-flex h-9 w-9 items-center justify-center rounded-md border transition-colors', children: currentLanguage.flag }), _jsx(Transition, { as: Fragment, enter: 'transition ease-out duration-100', enterFrom: 'transform opacity-0 scale-95', enterTo: 'transform opacity-100 scale-100', leave: 'transition ease-in duration-75', leaveFrom: 'transform opacity-100 scale-100', leaveTo: 'transform opacity-0 scale-95', children: _jsx(MenuItems, { anchor: 'bottom end', className: 'bg-popover border-border z-50 w-36 rounded-md border shadow-lg ring-1 ring-black/5 [--anchor-gap:4px] focus:outline-none', children: _jsx("div", { className: 'py-1', children: availableLanguages.map((language) => (_jsx(MenuItem, { children: _jsxs("button", { onClick: () => changeLanguage(language.code), className: 'data-[focus]:bg-accent data-[focus]:text-accent-foreground text-foreground group flex w-full items-center gap-2 px-3 py-2 text-sm transition-colors', children: [language.flag, _jsx("span", { children: language.name }), currentLocale === language.code && (_jsx("svg", { className: 'ml-auto h-4 w-4', fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24', children: _jsx("path", { strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 2, d: 'M5 13l4 4L19 7' }) }))] }) }, language.code))) }) }) })] }));
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/theme-switcher/index.tsx"],"names":[],"mappings":"AAMA,QAAA,MAAM,aAAa,+CAoElB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { useTheme } from 'next-themes';
|
|
5
|
+
const ThemeSwitcher = () => {
|
|
6
|
+
const { theme, setTheme } = useTheme();
|
|
7
|
+
const [mounted, setMounted] = React.useState(false);
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
setMounted(true);
|
|
10
|
+
}, []);
|
|
11
|
+
// Toggle between light and dark themes
|
|
12
|
+
const toggleTheme = () => {
|
|
13
|
+
setTheme(theme === 'dark' ? 'light' : 'dark');
|
|
14
|
+
};
|
|
15
|
+
if (!mounted) {
|
|
16
|
+
return (_jsx("button", { className: 'border-input bg-card 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' }) }));
|
|
17
|
+
}
|
|
18
|
+
return (_jsxs("button", { onClick: toggleTheme, className: 'border-input bg-card hover:bg-accent hover:text-accent-foreground relative inline-flex h-9 w-9 items-center justify-center rounded-md border transition-colors', "aria-label": `Switch theme (current: ${theme})`, title: `Theme: ${theme === 'light' ? 'Light' : 'Dark'} (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 ${theme !== 'dark' ? '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 ${theme === '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' }) })] }));
|
|
19
|
+
};
|
|
20
|
+
export default ThemeSwitcher;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface TooltipProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export default function Tooltip({ children, content }: TooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/tooltip/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAoB,MAAM,OAAO,CAAC;AAIpD,UAAU,YAAY;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,2CAyDlE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
|
+
import { arrow, autoUpdate, flip, offset, shift, useFloating, useHover, useInteractions } from '@floating-ui/react';
|
|
5
|
+
export default function Tooltip({ children, content }) {
|
|
6
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
7
|
+
const arrowRef = useRef(null);
|
|
8
|
+
const { refs, floatingStyles, context, middlewareData, placement } = useFloating({
|
|
9
|
+
open: isOpen,
|
|
10
|
+
onOpenChange: setIsOpen,
|
|
11
|
+
placement: 'top',
|
|
12
|
+
strategy: 'fixed',
|
|
13
|
+
middleware: [
|
|
14
|
+
offset(10),
|
|
15
|
+
flip({
|
|
16
|
+
fallbackAxisSideDirection: 'start',
|
|
17
|
+
crossAxis: false,
|
|
18
|
+
}),
|
|
19
|
+
shift({ padding: 8 }),
|
|
20
|
+
arrow({ element: arrowRef }),
|
|
21
|
+
],
|
|
22
|
+
whileElementsMounted: autoUpdate,
|
|
23
|
+
});
|
|
24
|
+
const hover = useHover(context);
|
|
25
|
+
const { getReferenceProps, getFloatingProps } = useInteractions([hover]);
|
|
26
|
+
// Determine which side the arrow should be on based on placement
|
|
27
|
+
const staticSide = {
|
|
28
|
+
top: 'bottom',
|
|
29
|
+
right: 'left',
|
|
30
|
+
bottom: 'top',
|
|
31
|
+
left: 'right',
|
|
32
|
+
}[placement.split('-')[0]];
|
|
33
|
+
return (_jsxs("div", { ref: refs.setReference, ...getReferenceProps(), className: 'inline-block', children: [children, isOpen && (_jsxs("div", { ref: refs.setFloating, style: floatingStyles, className: 'z-50 rounded bg-black px-2 py-1 text-sm text-white shadow-md dark:bg-white dark:text-black', ...getFloatingProps(), children: [content, _jsx("div", { ref: arrowRef, className: 'absolute h-2 w-2 rotate-45 bg-black dark:bg-white', style: {
|
|
34
|
+
left: middlewareData.arrow?.x != null ? `${middlewareData.arrow.x}px` : '',
|
|
35
|
+
top: middlewareData.arrow?.y != null ? `${middlewareData.arrow.y}px` : '',
|
|
36
|
+
right: '',
|
|
37
|
+
bottom: '',
|
|
38
|
+
[staticSide]: '-4px',
|
|
39
|
+
} })] }))] }));
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-lingui.d.ts","sourceRoot":"","sources":["../../src/i18n/init-lingui.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrC,CAAC;AAEF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,+BAKxC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Messages } from '@lingui/core';
|
|
2
|
+
import { I18n } from '@lingui/core';
|
|
3
|
+
import 'server-only';
|
|
4
|
+
type SupportedLocales = string;
|
|
5
|
+
type AllMessagesType = {
|
|
6
|
+
[key: string]: Messages;
|
|
7
|
+
};
|
|
8
|
+
export declare const allMessages: AllMessagesType;
|
|
9
|
+
type AllI18nInstances = {
|
|
10
|
+
[K in SupportedLocales]: I18n;
|
|
11
|
+
};
|
|
12
|
+
export declare const allI18nInstances: AllI18nInstances;
|
|
13
|
+
export declare const getI18nInstance: (locale: SupportedLocales) => I18n;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=lingui.setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lingui.setup.d.ts","sourceRoot":"","sources":["../../src/i18n/lingui.setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAa,MAAM,cAAc,CAAC;AAG/C,OAAO,aAAa,CAAC;AAIrB,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAe/B,KAAK,eAAe,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAC;AAGnD,eAAO,MAAM,WAAW,EAAE,eAKzB,CAAC;AAEF,KAAK,gBAAgB,GAAG;KAAG,CAAC,IAAI,gBAAgB,GAAG,IAAI;CAAE,CAAC;AAE1D,eAAO,MAAM,gBAAgB,EAAE,gBAQL,CAAC;AAE3B,eAAO,MAAM,eAAe,GAAI,QAAQ,gBAAgB,KAAG,IAM1D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { setupI18n } from '@lingui/core';
|
|
2
|
+
import linguiConfig from 'lingui.config';
|
|
3
|
+
import 'server-only';
|
|
4
|
+
const { locales } = linguiConfig;
|
|
5
|
+
async function loadCatalog(locale) {
|
|
6
|
+
const { messages } = await import(`lang/${locale}.po`);
|
|
7
|
+
return {
|
|
8
|
+
[locale]: messages,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const catalogs = await Promise.all(locales.map(loadCatalog));
|
|
12
|
+
// transform array of catalogs into a single object
|
|
13
|
+
export const allMessages = catalogs.reduce((acc, oneCatalog) => {
|
|
14
|
+
return { ...acc, ...oneCatalog };
|
|
15
|
+
}, {});
|
|
16
|
+
export const allI18nInstances = locales.reduce((acc, locale) => {
|
|
17
|
+
const messages = allMessages[locale] ?? {};
|
|
18
|
+
const i18n = setupI18n({
|
|
19
|
+
locale,
|
|
20
|
+
messages: { [locale]: messages },
|
|
21
|
+
});
|
|
22
|
+
return { ...acc, [locale]: i18n };
|
|
23
|
+
}, {});
|
|
24
|
+
export const getI18nInstance = (locale) => {
|
|
25
|
+
if (!allI18nInstances[locale]) {
|
|
26
|
+
console.warn(`No i18n instance found for locale "${locale}"`);
|
|
27
|
+
}
|
|
28
|
+
return allI18nInstances[locale] || allI18nInstances['en'];
|
|
29
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Messages } from '@lingui/core';
|
|
2
|
+
type Props = {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
initialLocale: string;
|
|
5
|
+
initialMessages: Messages;
|
|
6
|
+
};
|
|
7
|
+
export declare function LinguiClientProvider({ children, initialLocale, initialMessages }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=lingui-client-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lingui-client-provider.d.ts","sourceRoot":"","sources":["../../../src/i18n/providers/lingui-client-provider.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,QAAQ,EAAa,MAAM,cAAc,CAAC;AAGxD,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,QAAQ,CAAC;CAC3B,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,EAAE,KAAK,2CASvF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { setupI18n } from '@lingui/core';
|
|
5
|
+
import { I18nProvider } from '@lingui/react';
|
|
6
|
+
export function LinguiClientProvider({ children, initialLocale, initialMessages }) {
|
|
7
|
+
const [i18n] = useState(() => {
|
|
8
|
+
return setupI18n({
|
|
9
|
+
locale: initialLocale,
|
|
10
|
+
messages: { [initialLocale]: initialMessages },
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
return _jsx(I18nProvider, { i18n: i18n, children: children });
|
|
14
|
+
}
|