From 92a509ebb691ded4e6ada6b025f5a3bd43558098 Mon Sep 17 00:00:00 2001 From: corpi Date: Tue, 10 Mar 2026 13:30:09 +0900 Subject: [PATCH] =?UTF-8?q?feat(auth):=20=EB=9E=9C=EB=94=A9=20=EC=8B=9C?= =?UTF-8?q?=EC=9E=91=20=EB=B6=84=EA=B8=B0=EC=99=80=20=EC=95=B1=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=8A=B8=20=EA=B0=80=EB=93=9C=EB=A5=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(app)/layout.tsx | 19 + src/app/(landing)/page.tsx | 126 ++- .../auth/components/AuthRedirectButton.tsx | 47 ++ src/features/auth/model/constants.ts | 2 + src/shared/i18n/index.ts | 1 + src/shared/i18n/ko.ts | 716 ++++++++++++++++++ src/store/useAuthStore.ts | 5 +- 7 files changed, 848 insertions(+), 68 deletions(-) create mode 100644 src/app/(app)/layout.tsx create mode 100644 src/features/auth/components/AuthRedirectButton.tsx create mode 100644 src/features/auth/model/constants.ts create mode 100644 src/shared/i18n/index.ts create mode 100644 src/shared/i18n/ko.ts diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx new file mode 100644 index 0000000..ec542c4 --- /dev/null +++ b/src/app/(app)/layout.tsx @@ -0,0 +1,19 @@ +import type { ReactNode } from "react"; +import { cookies } from "next/headers"; +import { redirect } from "next/navigation"; +import { TOKEN_COOKIE_KEY } from "@/features/auth/model/constants"; + +interface AppLayoutProps { + children: ReactNode; +} + +export default async function AppLayout({ children }: AppLayoutProps) { + const cookieStore = await cookies(); + const accessToken = cookieStore.get(TOKEN_COOKIE_KEY)?.value; + + if (!accessToken) { + redirect("/login"); + } + + return children; +} diff --git a/src/app/(landing)/page.tsx b/src/app/(landing)/page.tsx index 18fd844..4fd128e 100644 --- a/src/app/(landing)/page.tsx +++ b/src/app/(landing)/page.tsx @@ -1,7 +1,11 @@ import Link from "next/link"; +import { copy } from '@/shared/i18n'; +import { AuthRedirectButton } from "@/features/auth/components/AuthRedirectButton"; import { Button } from "@/shared/ui/Button"; export default function MarketingPage() { + const { landing } = copy; + return (
@@ -9,14 +13,14 @@ export default function MarketingPage() {
- ๐Ÿชด VibeRoom + ๐Ÿชด {copy.appName}
@@ -27,19 +31,18 @@ export default function MarketingPage() {

- ํ•จ๊ป˜ํ•˜๋Š” ์กฐ์šฉํ•œ ๋ชฐ์ž…,
- VibeRoom + {landing.hero.titleLead}
+ {landing.hero.titleAccent}

- ์ง‘์ค‘ํ•˜๊ธฐ ์–ด๋ ค์šด ์ˆœ๊ฐ„, ๋‹น์‹ ์„ ๋‹ค๊ทธ์น˜์ง€ ์•Š๋Š” ํŽธ์•ˆํ•œ ๊ณต๊ฐ„์œผ๋กœ ๋“ค์–ด์˜ค์„ธ์š”. - ๊ตฌ์กฐํ™”๋œ ์ฝ”์›Œํ‚น ์„ธ์…˜๊ณผ ๋А์Šจํ•œ ์—ฐ๋Œ€๊ฐ€ ๋‹น์‹ ์˜ ํŽ˜์ด์Šค๋ฅผ ๋˜์ฐพ์•„ ์ค๋‹ˆ๋‹ค. + {landing.hero.description}

- + + {landing.hero.primaryCta} +
@@ -64,7 +67,7 @@ export default function MarketingPage() {
- 45:00 ๋‚จ์Œ + {landing.hero.timerPreview}
@@ -76,23 +79,19 @@ export default function MarketingPage() {
-

๋‹น์‹ ์„ ์œ„ํ•œ ๋‹ค์ •ํ•œ ๋ชฐ์ž… ์žฅ์น˜

-

๋‹จ์ˆœํ•œ ํƒ€์ด๋จธ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ฌด๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์˜ค๋ž˜ ์ง€์†ํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

+

{landing.features.title}

+

{landing.features.description}

- {[ - { icon: "โณ", title: "๊ตฌ์กฐํ™”๋œ ์„ธ์…˜ ํƒ€์ด๋จธ", desc: "๋ถ€๋‹ด ์—†์ด ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์งง์€ ๋ชฐ์ž…๊ณผ ํ™•์‹คํ•œ ํœด์‹. ๋‹น์‹ ๋งŒ์˜ ์ž‘์—… ๋ฆฌ๋“ฌ์„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์„ค์ •ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜์„ธ์š”." }, - { icon: "๐ŸŒฑ", title: "๋‹ค์ •ํ•œ ์—ฐ๋Œ€์™€ ์ฝ”์›Œํ‚น", desc: "ํ™”๋ฉด ๋„ˆ๋จธ ๋ˆ„๊ตฐ๊ฐ€์™€ ํ•จ๊ป˜ํ•˜๋Š” ๋ฐ”๋”” ๋”๋ธ”๋ง ํšจ๊ณผ. ๊ฐ์‹œ๊ฐ€ ์•„๋‹Œ, ์กฐ์šฉํ•˜์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ๋™๊ธฐ๋ฅผ ์„œ๋กœ ๋‚˜๋ˆ„์–ด๋ณด์„ธ์š”." }, - { icon: "๐Ÿ›‹๏ธ", title: "๋‚˜๋งŒ์˜ ์‹ฌ๋ฏธ์  ๊ณต๊ฐ„", desc: "๋น„ ์˜ค๋Š” ๋‹ค๋ฝ๋ฐฉ, ํ–‡์‚ด ๋“œ๋Š” ์นดํŽ˜. ๋ฐฑ์ƒ‰์†Œ์Œ๊ณผ ํ•จ๊ป˜ ๋‚ด๊ฐ€ ๊ฐ€์žฅ ํŽธ์•ˆํ•จ์„ ๋А๋ผ๋Š” ๊ฐ€์ƒ ๊ณต๊ฐ„์„ ๊พธ๋ฏธ๊ณ  ๋จธ๋ฌด๋ฅด์„ธ์š”." } - ].map((feature, idx) => ( + {landing.features.items.map((feature, idx) => (
{feature.icon}

{feature.title}

- {feature.desc} + {feature.description}

))} @@ -104,65 +103,64 @@ export default function MarketingPage() {
-

๋‚˜์—๊ฒŒ ๋งž๋Š” ๊ณต๊ฐ„ ์„ ํƒํ•˜๊ธฐ

-

๊ฐœ์ธ์˜ ๊ฐ€๋ฒผ์šด ์ง‘์ค‘๋ถ€ํ„ฐ ํ”„๋ฆฌ๋žœ์„œ์˜ ์™„๋ฒฝํ•œ ์›Œํฌ์ŠคํŽ˜์ด์Šค๊นŒ์ง€.

+

{landing.pricing.title}

+

{landing.pricing.description}

{/* Starter Plan */}
-

Starter

-

๊ฐ€๋ฒผ์šด ์ง‘์ค‘์ด ํ•„์š”ํ•œ ๋ถ„

+

{landing.pricing.plans.starter.name}

+

{landing.pricing.plans.starter.subtitle}

- ๋ฌด๋ฃŒ + {landing.pricing.plans.starter.price}
    -
  • โœ“ ๊ธฐ๋ณธ ๊ฐ€์ƒ ๊ณต๊ฐ„ ํ…Œ๋งˆ
  • -
  • โœ“ 1:1 ํŒŒํŠธ๋„ˆ ๋งค์นญ (์ฃผ 3ํšŒ)
  • -
  • โœ“ ์˜คํ”ˆ ์ฝ”์›Œํ‚น ๋ฃธ ์ž…์žฅ
  • + {landing.pricing.plans.starter.features.map((feature) => ( +
  • โœ“{feature}
  • + ))}
- + + {landing.pricing.plans.starter.cta} +
{/* Pro Plan */}
- ์ถ”์ฒœ + {landing.pricing.plans.pro.badge}
-

Pro

-

๋ฐฉํ•ด ์—†๋Š” ์™„๋ฒฝํ•œ ๋ชฐ์ž… ํ™˜๊ฒฝ

+

{landing.pricing.plans.pro.name}

+

{landing.pricing.plans.pro.subtitle}

- โ‚ฉ6,900 - /์›” + {landing.pricing.plans.pro.price} + {landing.pricing.plans.pro.priceSuffix}
    -
  • โœ“ ํ”„๋ฆฌ๋ฏธ์—„ ํ…Œ๋งˆ ๋ฌด์ œํ•œ
  • -
  • โœ“ 1:1 ๋งค์นญ ๋ฌด์ œํ•œ
  • -
  • โœ“ ๊ณ ๊ธ‰ ์ง‘์ค‘ ํ†ต๊ณ„ ๋ฐ ๋ฆฌํฌํŠธ
  • -
  • โœ“ ๊ณต๊ฐ„ ์ปค์Šคํ…€ ์•„์ดํ…œ ์ œ๊ณต
  • + {landing.pricing.plans.pro.features.map((feature) => ( +
  • โœ“{feature}
  • + ))}
- + + {landing.pricing.plans.pro.cta} +
{/* Teams Plan */}
-

Teams

-

๋ฆฌ๋ชจํŠธ ์›Œํฌ ๊ธฐ์—… ๋ฐ ํŒ€

+

{landing.pricing.plans.teams.name}

+

{landing.pricing.plans.teams.subtitle}

- โ‚ฉ12,000 - /์ธยท์›” + {landing.pricing.plans.teams.price} + {landing.pricing.plans.teams.priceSuffix}
    -
  • โœ“ Pro ํ”Œ๋žœ์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ
  • -
  • โœ“ ํ”„๋ผ์ด๋น— ํŒ€ ์ŠคํŽ˜์ด์Šค
  • -
  • โœ“ ํŒ€ ์ „์ฒด ์ƒ์‚ฐ์„ฑ ๋Œ€์‹œ๋ณด๋“œ
  • + {landing.pricing.plans.teams.features.map((feature) => ( +
  • โœ“{feature}
  • + ))}
@@ -176,31 +174,31 @@ export default function MarketingPage() {
- ๐Ÿชด VibeRoom + ๐Ÿชด {copy.appName}

- ํ”„๋ฆฌ๋žœ์„œ์™€ ์˜จ์ „ํ•œ ์ง‘์ค‘์ด ํ•„์š”ํ•œ ๋ถ„๋“ค์„ ์œ„ํ•œ ๋”ฐ๋œปํ•˜๊ณ  ๊ตฌ์กฐํ™”๋œ ์˜จ๋ผ์ธ ์ฝ”์›Œํ‚น ์ŠคํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. + {landing.footer.description}

-

์ œํ’ˆ

+

{landing.footer.productTitle}

- © 2026 VibeRoom. All rights reserved. + {landing.footer.copyright}
diff --git a/src/features/auth/components/AuthRedirectButton.tsx b/src/features/auth/components/AuthRedirectButton.tsx new file mode 100644 index 0000000..274859d --- /dev/null +++ b/src/features/auth/components/AuthRedirectButton.tsx @@ -0,0 +1,47 @@ +"use client"; + +import type { ReactNode } from "react"; +import Cookies from "js-cookie"; +import { useRouter } from "next/navigation"; +import { TOKEN_COOKIE_KEY } from "@/features/auth/model/constants"; +import { Button, type ButtonSize, type ButtonVariant } from "@/shared/ui/Button"; +import { useAuthStore } from "@/store/useAuthStore"; + +interface AuthRedirectButtonProps { + children: ReactNode; + className?: string; + size?: ButtonSize; + variant?: ButtonVariant; + authenticatedHref?: string; + unauthenticatedHref?: string; +} + +export function AuthRedirectButton({ + children, + className, + size = "md", + variant = "primary", + authenticatedHref = "/space", + unauthenticatedHref = "/login", +}: AuthRedirectButtonProps) { + const router = useRouter(); + const accessToken = useAuthStore((state) => state.accessToken); + const isAuthenticated = useAuthStore((state) => state.isAuthenticated); + + const handleClick = () => { + const hasAccessToken = isAuthenticated || Boolean(accessToken) || Boolean(Cookies.get(TOKEN_COOKIE_KEY)); + router.push(hasAccessToken ? authenticatedHref : unauthenticatedHref); + }; + + return ( + + ); +} diff --git a/src/features/auth/model/constants.ts b/src/features/auth/model/constants.ts new file mode 100644 index 0000000..78eee73 --- /dev/null +++ b/src/features/auth/model/constants.ts @@ -0,0 +1,2 @@ +export const TOKEN_COOKIE_KEY = "vr_access_token"; +export const REFRESH_TOKEN_COOKIE_KEY = "vr_refresh_token"; diff --git a/src/shared/i18n/index.ts b/src/shared/i18n/index.ts new file mode 100644 index 0000000..f88fe5a --- /dev/null +++ b/src/shared/i18n/index.ts @@ -0,0 +1 @@ +export { ko as copy } from './ko'; diff --git a/src/shared/i18n/ko.ts b/src/shared/i18n/ko.ts new file mode 100644 index 0000000..8c6dd03 --- /dev/null +++ b/src/shared/i18n/ko.ts @@ -0,0 +1,716 @@ +export const ko = { + appName: 'VibeRoom', + metadata: { + title: 'VibeRoom - ๋‹น์‹ ๋งŒ์˜ ํŽธ์•ˆํ•œ ๋ชฐ์ž… ๊ณต๊ฐ„', + description: + 'ํ”„๋ฆฌ๋žœ์„œ์™€ ์˜จ์ „ํ•œ ์ง‘์ค‘์ด ํ•„์š”ํ•œ ๋ถ„๋“ค์„ ์œ„ํ•œ ๋”ฐ๋œปํ•˜๊ณ  ๊ตฌ์กฐํ™”๋œ ์˜จ๋ผ์ธ ์ฝ”์›Œํ‚น ์ŠคํŽ˜์ด์Šค. ์ž‘์—… ํƒ€์ด๋จธ, ์„ธ์…˜ ๊ด€๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ๋А์Šจํ•œ ์—ฐ๋Œ€๋ฅผ ํ†ตํ•ด ๋‹น์‹ ์˜ ๋ฆฌ๋“ฌ์„ ์ฐพ์•„๋ณด์„ธ์š”.', + }, + common: { + close: '๋‹ซ๊ธฐ', + cancel: '์ทจ์†Œ', + save: '์ €์žฅ', + delete: '์‚ญ์ œ', + complete: '์™„๋ฃŒ', + select: '์„ ํƒ', + hub: 'ํ—ˆ๋ธŒ๋กœ', + loading: '๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ด์—์š”.', + default: '๊ธฐ๋ณธ', + defaultBackground: '๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ', + admin: '๊ด€๋ฆฌ์ž', + requestFailed: (status: number) => `์š”์ฒญ ์‹คํŒจ: ${status}`, + apiRequestFailed: (status: number) => `API ์š”์ฒญ ์‹คํŒจ: ${status}`, + }, + landing: { + nav: { + features: '๊ธฐ๋Šฅ ์†Œ๊ฐœ', + pricing: '์š”๊ธˆ์ œ', + login: '๋กœ๊ทธ์ธ', + startFree: '๋ฌด๋ฃŒ๋กœ ์‹œ์ž‘ํ•˜๊ธฐ', + }, + hero: { + titleLead: 'ํ•จ๊ป˜ํ•˜๋Š” ์กฐ์šฉํ•œ ๋ชฐ์ž…,', + titleAccent: 'VibeRoom', + description: + '์ง‘์ค‘ํ•˜๊ธฐ ์–ด๋ ค์šด ์ˆœ๊ฐ„, ๋‹น์‹ ์„ ๋‹ค๊ทธ์น˜์ง€ ์•Š๋Š” ํŽธ์•ˆํ•œ ๊ณต๊ฐ„์œผ๋กœ ๋“ค์–ด์˜ค์„ธ์š”. ๊ตฌ์กฐํ™”๋œ ์ฝ”์›Œํ‚น ์„ธ์…˜๊ณผ ๋А์Šจํ•œ ์—ฐ๋Œ€๊ฐ€ ๋‹น์‹ ์˜ ํŽ˜์ด์Šค๋ฅผ ๋˜์ฐพ์•„ ์ค๋‹ˆ๋‹ค.', + primaryCta: '๋‚˜๋งŒ์˜ ๊ณต๊ฐ„ ๋งŒ๋“ค๊ธฐ', + secondaryCta: '๋” ์•Œ์•„๋ณด๊ธฐ', + timerPreview: '45:00 ๋‚จ์Œ', + }, + features: { + title: '๋‹น์‹ ์„ ์œ„ํ•œ ๋‹ค์ •ํ•œ ๋ชฐ์ž… ์žฅ์น˜', + description: '๋‹จ์ˆœํ•œ ํƒ€์ด๋จธ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ฌด๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์˜ค๋ž˜ ์ง€์†ํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.', + items: [ + { + icon: 'โณ', + title: '๊ตฌ์กฐํ™”๋œ ์„ธ์…˜ ํƒ€์ด๋จธ', + description: + '๋ถ€๋‹ด ์—†์ด ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์งง์€ ๋ชฐ์ž…๊ณผ ํ™•์‹คํ•œ ํœด์‹. ๋‹น์‹ ๋งŒ์˜ ์ž‘์—… ๋ฆฌ๋“ฌ์„ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์„ค์ •ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜์„ธ์š”.', + }, + { + icon: '๐ŸŒฑ', + title: '๋‹ค์ •ํ•œ ์—ฐ๋Œ€์™€ ์ฝ”์›Œํ‚น', + description: + 'ํ™”๋ฉด ๋„ˆ๋จธ ๋ˆ„๊ตฐ๊ฐ€์™€ ํ•จ๊ป˜ํ•˜๋Š” ๋ฐ”๋”” ๋”๋ธ”๋ง ํšจ๊ณผ. ๊ฐ์‹œ๊ฐ€ ์•„๋‹Œ, ์กฐ์šฉํ•˜์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ๋™๊ธฐ๋ฅผ ์„œ๋กœ ๋‚˜๋ˆ„์–ด๋ณด์„ธ์š”.', + }, + { + icon: '๐Ÿ›‹๏ธ', + title: '๋‚˜๋งŒ์˜ ์‹ฌ๋ฏธ์  ๊ณต๊ฐ„', + description: + '๋น„ ์˜ค๋Š” ๋‹ค๋ฝ๋ฐฉ, ํ–‡์‚ด ๋“œ๋Š” ์นดํŽ˜. ๋ฐฑ์ƒ‰์†Œ์Œ๊ณผ ํ•จ๊ป˜ ๋‚ด๊ฐ€ ๊ฐ€์žฅ ํŽธ์•ˆํ•จ์„ ๋А๋ผ๋Š” ๊ฐ€์ƒ ๊ณต๊ฐ„์„ ๊พธ๋ฏธ๊ณ  ๋จธ๋ฌด๋ฅด์„ธ์š”.', + }, + ], + }, + pricing: { + title: '๋‚˜์—๊ฒŒ ๋งž๋Š” ๊ณต๊ฐ„ ์„ ํƒํ•˜๊ธฐ', + description: '๊ฐœ์ธ์˜ ๊ฐ€๋ฒผ์šด ์ง‘์ค‘๋ถ€ํ„ฐ ํ”„๋ฆฌ๋žœ์„œ์˜ ์™„๋ฒฝํ•œ ์›Œํฌ์ŠคํŽ˜์ด์Šค๊นŒ์ง€.', + plans: { + starter: { + name: 'Starter', + subtitle: '๊ฐ€๋ฒผ์šด ์ง‘์ค‘์ด ํ•„์š”ํ•œ ๋ถ„', + price: '๋ฌด๋ฃŒ', + cta: '๋ฌด๋ฃŒ๋กœ ์‹œ์ž‘ํ•˜๊ธฐ', + features: ['๊ธฐ๋ณธ ๊ฐ€์ƒ ๊ณต๊ฐ„ ํ…Œ๋งˆ', '1:1 ํŒŒํŠธ๋„ˆ ๋งค์นญ (์ฃผ 3ํšŒ)', '์˜คํ”ˆ ์ฝ”์›Œํ‚น ๋ฃธ ์ž…์žฅ'], + }, + pro: { + badge: '์ถ”์ฒœ', + name: 'Pro', + subtitle: '๋ฐฉํ•ด ์—†๋Š” ์™„๋ฒฝํ•œ ๋ชฐ์ž… ํ™˜๊ฒฝ', + price: 'โ‚ฉ6,900', + priceSuffix: '/์›”', + cta: 'Pro ์‹œ์ž‘ํ•˜๊ธฐ', + features: [ + 'ํ”„๋ฆฌ๋ฏธ์—„ ํ…Œ๋งˆ ๋ฌด์ œํ•œ', + '1:1 ๋งค์นญ ๋ฌด์ œํ•œ', + '๊ณ ๊ธ‰ ์ง‘์ค‘ ํ†ต๊ณ„ ๋ฐ ๋ฆฌํฌํŠธ', + '๊ณต๊ฐ„ ์ปค์Šคํ…€ ์•„์ดํ…œ ์ œ๊ณต', + ], + }, + teams: { + name: 'Teams', + subtitle: '๋ฆฌ๋ชจํŠธ ์›Œํฌ ๊ธฐ์—… ๋ฐ ํŒ€', + price: 'โ‚ฉ12,000', + priceSuffix: '/์ธยท์›”', + cta: '๋„์ž… ๋ฌธ์˜ํ•˜๊ธฐ', + features: ['Pro ํ”Œ๋žœ์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ', 'ํ”„๋ผ์ด๋น— ํŒ€ ์ŠคํŽ˜์ด์Šค', 'ํŒ€ ์ „์ฒด ์ƒ์‚ฐ์„ฑ ๋Œ€์‹œ๋ณด๋“œ'], + }, + }, + }, + footer: { + description: + 'ํ”„๋ฆฌ๋žœ์„œ์™€ ์˜จ์ „ํ•œ ์ง‘์ค‘์ด ํ•„์š”ํ•œ ๋ถ„๋“ค์„ ์œ„ํ•œ ๋”ฐ๋œปํ•˜๊ณ  ๊ตฌ์กฐํ™”๋œ ์˜จ๋ผ์ธ ์ฝ”์›Œํ‚น ์ŠคํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.', + productTitle: '์ œํ’ˆ', + companyTitle: 'ํšŒ์‚ฌ', + links: { + features: '๊ธฐ๋Šฅ ์†Œ๊ฐœ', + pricing: '์š”๊ธˆ์ œ', + webLogin: '์›น์•ฑ ๋กœ๊ทธ์ธ', + about: '์†Œ๊ฐœ', + privacy: '๊ฐœ์ธ์ •๋ณด์ฒ˜๋ฆฌ๋ฐฉ์นจ', + terms: '์ด์šฉ์•ฝ๊ด€', + }, + copyright: 'ยฉ 2026 VibeRoom. All rights reserved.', + }, + }, + login: { + title: '๋‹ค์‹œ ์˜ค์…จ๊ตฐ์š”!', + descriptionFirstLine: '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์™ธ์šธ ํ•„์š” ์—†์ด,', + descriptionSecondLine: '์‚ฌ์šฉ ์ค‘์ธ ๊ณ„์ •์œผ๋กœ 3์ดˆ ๋งŒ์— ์‹œ์ž‘ํ•˜์„ธ์š”.', + agreementPrefix: '๋กœ๊ทธ์ธํ•จ์œผ๋กœ์จ VibeRoom์˜', + agreementAnd: '๋ฐ', + terms: '์ด์šฉ์•ฝ๊ด€', + privacy: '๊ฐœ์ธ์ •๋ณด์ฒ˜๋ฆฌ๋ฐฉ์นจ', + agreementSuffix: '์— ๋™์˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.', + }, + auth: { + social: { + connecting: '์—ฐ๊ฒฐ ์ค‘...', + continueWithGoogle: 'Google๋กœ ๊ณ„์†ํ•˜๊ธฐ', + continueWithApple: 'Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ', + continueWithFacebook: 'Facebook์œผ๋กœ ๊ณ„์†ํ•˜๊ธฐ', + }, + errors: { + loginFailed: '๋กœ๊ทธ์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”.', + googleFailed: '๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ํŒ์—… ์ฐจ๋‹จ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด ์ฃผ์„ธ์š”.', + appleFailed: '์• ํ”Œ ๋กœ๊ทธ์ธ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.', + appleInitFailed: '์• ํ”Œ ๋กœ๊ทธ์ธ ์ดˆ๊ธฐํ™” ์‹คํŒจ', + facebookFailed: 'ํŽ˜์ด์Šค๋ถ ๋กœ๊ทธ์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + }, + }, + admin: { + defaultLoginId: 'qwer1234', + defaultPassword: 'qwer1234!', + consoleLabel: 'Admin Console', + mediaAdminLabel: 'Media Admin', + localCredentialsHint: 'Local admin credentials', + signInEyebrow: 'Sign In', + loginTitle: '๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ', + loginDescription: '๊ด€๋ฆฌ์ž ๊ถŒํ•œ์ด ํ™•์ธ๋˜๋ฉด ์ขŒ์ธก ์‚ฌ์ด๋“œ๋ฐ” ๊ธฐ๋ฐ˜ ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ์—ด๋ฆฝ๋‹ˆ๋‹ค.', + loginIdLabel: '์•„์ด๋””', + loginPasswordLabel: '๋น„๋ฐ€๋ฒˆํ˜ธ', + openDashboard: '๋Œ€์‹œ๋ณด๋“œ ์—ด๊ธฐ', + loggingIn: '๋กœ๊ทธ์ธ ์ค‘...', + logout: '๋กœ๊ทธ์•„์›ƒ', + mediaOperations: 'Media Operations', + access: 'Access', + accessTitle: 'Admin Only', + accessDescription: '๋กœ๊ทธ์ธ ํ›„ ์—…๋กœ๋“œ ํ† ํฐ์œผ๋กœ scene ์ด๋ฏธ์ง€์™€ sound ์˜ค๋””์˜ค๋ฅผ ๋ฐ”๋กœ R2์— ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.', + manifestReady: 'Manifest Ready', + sessionSection: 'Session', + sessionAdminLabel: 'Admin', + sessionRoleLabel: 'Role', + roleAccessSuffix: ' Access', + searchValues: { + scene: 'scene assets', + sound: 'sound assets', + }, + navItems: [ + { + id: 'scene', + title: '์ด๋ฏธ์ง€ ๋“ฑ๋ก', + subtitle: 'Scene background assets', + section: 'MEDIA', + }, + { + id: 'sound', + title: '์˜ค๋””์˜ค ๋“ฑ๋ก', + subtitle: 'Loop and preview assets', + section: 'MEDIA', + }, + ], + views: { + scene: { + eyebrow: 'Image Registration', + title: 'Scene ์ด๋ฏธ์ง€ ๋“ฑ๋ก', + description: + 'Space์— ๋“ค์–ด์˜จ ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•˜๋Š” ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์„ธํŠธ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. cardFile๊ณผ stageFile์€ ์ตœ์ดˆ ์ƒ์„ฑ ์‹œ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.', + statTitle: 'Image Pipeline', + statValue: 'Scene Assets', + statHint: 'R2 / Manifest Sync', + workspaceTitle: '์ด๋ฏธ์ง€ ๋“ฑ๋ก ์›Œํฌ์ŠคํŽ˜์ด์Šค', + workspaceDescription: '์™ผ์ชฝ ๋ฉ”๋‰ด๋Š” ์œ ์ง€๋˜๊ณ , ์ด ์ค‘์•™ ์˜์—ญ๋งŒ `์ด๋ฏธ์ง€ ๋“ฑ๋ก` ์ž‘์—…์œผ๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.', + sceneIdLabel: 'Scene ID', + sceneIdPlaceholder: 'rain-window', + placeholderGradientLabel: 'Placeholder Gradient', + placeholderGradientPlaceholder: 'linear-gradient(160deg, #1e293b 0%, #0f172a 100%)', + cardImageLabel: 'Card Image', + stageImageLabel: 'Stage Image', + mobileStageLabel: 'Mobile Stage', + hdStageLabel: 'HD Stage', + blurDataUrlLabel: 'Blur Data URL', + blurDataUrlPlaceholder: 'data:image/jpeg;base64,...', + notesTitle: '์—…๋กœ๋“œ ๋ฉ”๋ชจ', + notes: [ + '์ตœ์ดˆ ์ƒ์„ฑ ์‹œ `cardFile`, `stageFile`์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.', + '๋ชจ๋ฐ”์ผ๊ณผ HD ํŒŒ์ผ์€ ์„ ํƒ๊ฐ’์ด๋ฉฐ ๋น ์ง€๋ฉด ๊ธฐ์กด ๊ฐ’์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.', + '์—…๋กœ๋“œ ์ฆ‰์‹œ R2 ๊ฒฝ๋กœ์™€ manifest ์‘๋‹ต ๊ฐ’์ด ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.', + ], + submit: '์ด๋ฏธ์ง€ ๋“ฑ๋ก', + pending: '์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์ค‘...', + }, + sound: { + eyebrow: 'Audio Registration', + title: 'Sound ์˜ค๋””์˜ค ๋“ฑ๋ก', + description: + 'Loop, preview, fallback ์˜ค๋””์˜ค๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. loopFile์€ ์ตœ์ดˆ ์ƒ์„ฑ ์‹œ ํ•„์ˆ˜์ด๋ฉฐ ๊ธฐ๋ณธ ๋ณผ๋ฅจ๊ณผ duration ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.', + statTitle: 'Audio Pipeline', + statValue: 'Sound Assets', + statHint: 'Loop / Preview / Fallback', + workspaceTitle: '์˜ค๋””์˜ค ๋“ฑ๋ก ์›Œํฌ์ŠคํŽ˜์ด์Šค', + workspaceDescription: '์ขŒ์ธก ๋„ค๋น„๊ฒŒ์ด์…˜์€ ๊ณ ์ •๋˜๊ณ , ์ด ์ค‘์•™ ์˜์—ญ๋งŒ `์˜ค๋””์˜ค ๋“ฑ๋ก` ์ž‘์—…์œผ๋กœ ๋ฐ”๋€๋‹ˆ๋‹ค.', + presetIdLabel: 'Preset ID', + presetIdPlaceholder: 'rain-focus', + durationLabel: 'Duration Sec', + durationPlaceholder: '1800', + defaultVolumeLabel: 'Default Volume', + defaultVolumePlaceholder: '60', + loopFileLabel: 'Loop File', + previewFileLabel: 'Preview File', + fallbackLoopFileLabel: 'Fallback Loop File', + notesTitle: '์—…๋กœ๋“œ ๋ฉ”๋ชจ', + notes: [ + '์ตœ์ดˆ ์ƒ์„ฑ ์‹œ `loopFile`์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.', + '`preview`, `fallback`์€ ์„ ํƒ๊ฐ’์ด๋ฉฐ ๊ธฐ์กด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.', + '`defaultVolume`, `durationSec`๋Š” manifest ์‘๋‹ต์— ํ•จ๊ป˜ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.', + ], + submit: '์˜ค๋””์˜ค ๋“ฑ๋ก', + pending: '์˜ค๋””์˜ค ์—…๋กœ๋“œ ์ค‘...', + }, + }, + inspector: { + recentResponse: '์ตœ๊ทผ ์‘๋‹ต', + noUploadSummary: '์•„์ง ์—…๋กœ๋“œ ์ž‘์—…์ด ์—†์Šต๋‹ˆ๋‹ค.', + noUploadPayload: '์—…๋กœ๋“œ ์‘๋‹ต์ด ์•„์ง ์—†์Šต๋‹ˆ๋‹ค.', + sessionToken: '์„ธ์…˜ ํ† ํฐ', + currentRoleTitle: 'Current Role', + bearerTokenSession: 'Bearer token enabled session', + }, + messages: { + nonAdmin: 'ADMIN ๊ถŒํ•œ์ด ์—†๋Š” ๊ณ„์ •์ž…๋‹ˆ๋‹ค.', + loginFailed: '๋กœ๊ทธ์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + loginRequired: '๋จผ์ € ๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ์„ ํ•ด์ฃผ์„ธ์š”.', + sceneIdRequired: 'sceneId๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', + presetIdRequired: 'presetId๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', + sceneUploadFailed: 'scene ์—…๋กœ๋“œ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + soundUploadFailed: 'sound ์—…๋กœ๋“œ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + sceneUploadDone: (sceneId: string) => `scene "${sceneId}" ์—…๋กœ๋“œ๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, + soundUploadDone: (presetId: string) => `sound "${presetId}" ์—…๋กœ๋“œ๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, + sceneSummary: (sceneId: string, version: string) => + `${sceneId} ์ด๋ฏธ์ง€ ์„ธํŠธ๊ฐ€ ์ตœ์‹  ๋ฒ„์ „ ${version}๋กœ ๋ฐ˜์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, + soundSummary: (presetId: string, version: string) => + `${presetId} ์˜ค๋””์˜ค ์„ธํŠธ๊ฐ€ ์ตœ์‹  ๋ฒ„์ „ ${version}๋กœ ๋ฐ˜์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`, + }, + }, + settings: { + title: 'Settings', + focusPreferencesApi: 'Focus Preferences API', + loading: '์ €์žฅ๋œ ์„ค์ •์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ด์—์š”.', + saving: '๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ €์žฅํ•˜๋Š” ์ค‘์ด์—์š”.', + synced: '๋ณ€๊ฒฝ ์ฆ‰์‹œ ์„œ๋ฒ„์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.', + reduceMotionTitle: 'Reduce Motion', + reduceMotionDescription: '์ „ํ™˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค. (UI ํ† ๊ธ€ ๋ชฉ์—…)', + notificationIntensityTitle: '์•Œ๋ฆผ ๊ฐ•๋„', + notificationIntensityDescription: '์ง‘์ค‘ ์‹œ์ž‘/์ข…๋ฃŒ ์‹ ํ˜ธ์˜ ์กด์žฌ๊ฐ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.', + defaultPresetTitle: '๊ธฐ๋ณธ ํ”„๋ฆฌ์…‹', + defaultPresetDescription: '์ž…์žฅ ์‹œ ์ž๋™ ์„ ํƒ๋  ์ถ”์ฒœ ์„ธํŠธ๋ฅผ ๊ณ ๋ฆ…๋‹ˆ๋‹ค.', + notificationIntensityOptions: ['์กฐ์šฉํ•จ', '๊ธฐ๋ณธ', '๊ฐ•ํ•จ'], + defaultPresetOptions: [ + { id: 'balanced', label: 'Balanced 25/5 + Rain Focus' }, + { id: 'deep-work', label: 'Deep Work 50/10 + Deep White' }, + { id: 'gentle', label: 'Gentle 25/5 + Silent' }, + ], + }, + stats: { + title: 'Stats', + apiLabel: 'API', + mockLabel: 'Mock', + sourceApi: 'API ํ†ต๊ณ„ ์‚ฌ์šฉ ์ค‘', + sourceMock: 'API ์‹คํŒจ๋กœ mock ํ†ต๊ณ„ ํ‘œ์‹œ ์ค‘', + loading: 'ํ†ต๊ณ„๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ด์—์š”.', + loadFailed: 'ํ†ต๊ณ„๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์–ด์š”.', + synced: 'ํ™”๋ฉด ์ง„์ž… ์‹œ ์ตœ์‹  ์š”์•ฝ์„ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.', + refresh: '์ƒˆ๋กœ๊ณ ์นจ', + today: '์˜ค๋Š˜', + last7Days: '์ตœ๊ทผ 7์ผ', + chartTitle: '์ง‘์ค‘ ํ๋ฆ„ ๊ทธ๋ž˜ํ”„', + chartWithTrend: 'trend ์‘๋‹ต์œผ๋กœ ๊ฐ„๋‹จํ•œ ๋ง‰๋Œ€ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.', + chartWithoutTrend: 'trend ์‘๋‹ต์ด ๋น„์–ด ์žˆ์–ด ํ”Œ๋ ˆ์ด์Šคํ™€๋” ์ƒํƒœ์ž…๋‹ˆ๋‹ค.', + todayFocus: '์˜ค๋Š˜ ์ง‘์ค‘ ์‹œ๊ฐ„', + completedCycles: '์™„๋ฃŒํ•œ ์‚ฌ์ดํด', + sessionEntries: '์ž…์žฅ ํšŸ์ˆ˜', + last7DaysFocus: '์ตœ๊ทผ 7์ผ ์ง‘์ค‘ ์‹œ๊ฐ„', + bestDay: '์ตœ๊ณ  ๋ชฐ์ž…์ผ', + streak: '์—ฐ์† ๋‹ฌ์„ฑ', + syncedApi: '๋™๊ธฐํ™”๋จ', + temporary: '์ž„์‹œ๊ฐ’', + actualAggregate: '์‹ค์ง‘๊ณ„', + mockAggregate: '๋ชฉ์—…', + streakActive: '์œ ์ง€ ์ค‘', + streakStart: '์‹œ์ž‘ ์ „', + countUnit: 'ํšŒ', + dayUnit: '์ผ', + minuteUnit: '๋ถ„', + barTitle: (date: string, minutes: number) => `${date} ยท ${minutes}๋ถ„`, + }, + plan: { + proFeatureCards: [ + { + id: 'scene-packs', + name: 'Scene Packs', + description: 'ํ”„๋ฆฌ๋ฏธ์—„ ๊ณต๊ฐ„ ๋ฌถ์Œ๊ณผ ์žฅ๋ฉด ๋ณ€์ฃผ', + }, + { + id: 'sound-packs', + name: 'Sound Packs', + description: 'ํ™•์žฅ ์‚ฌ์šด๋“œ ํ”„๋ฆฌ์…‹ ๋ฌถ์Œ', + }, + { + id: 'profiles', + name: 'Profiles', + description: '๋‚ด ๊ธฐ๋ณธ ์„ธํŒ… ์ €์žฅ/๋ถˆ๋Ÿฌ์˜ค๊ธฐ', + }, + ], + }, + session: { + todayOneLiner: '์˜ค๋Š˜์˜ ํ•œ ์ค„: ์™„๋ฒฝ๋ณด๋‹ค ์‹œ์ž‘, ํ•œ ์กฐ๊ฐ์ด๋ฉด ์ถฉ๋ถ„ํ•ด์š”.', + goalChips: [ + { id: 'mail-3', label: '๋ฉ”์ผ 3๊ฐœ' }, + { id: 'doc-1p', label: '๋ฌธ์„œ 1p' }, + { id: 'code-1-function', label: '์ฝ”๋”ฉ 1ํ•จ์ˆ˜' }, + { id: 'tidy-10m', label: '์ •๋ฆฌ 10๋ถ„' }, + { id: 'reading-15m', label: '๋…์„œ 15๋ถ„' }, + { id: 'resume-1paragraph', label: '์ด๋ ฅ์„œ 1๋ฌธ๋‹จ' }, + ], + checkInPhrases: [ + { id: 'arrived', text: '์ง€๊ธˆ ๋“ค์–ด์™”์–ด์š”' }, + { id: 'sprint-25', text: '25๋ถ„๋งŒ ๋‹ฌ๋ฆด๊ฒŒ์š”' }, + { id: 'on-break', text: 'ํœด์‹ ์ค‘' }, + { id: 'back-focus', text: '๋‹ค์‹œ ์ง‘์ค‘!' }, + { id: 'slow-day', text: '์˜ค๋Š˜์€ ์ฒœ์ฒœํžˆ' }, + ], + reactionOptions: [ + { id: 'thumbs-up', emoji: '๐Ÿ‘', label: '์‘์›ํ•ด์š”' }, + { id: 'fire', emoji: '๐Ÿ”ฅ', label: '์ง‘์ค‘ ๋ชจ๋“œ' }, + { id: 'clap', emoji: '๐Ÿ‘', label: '์ž˜ํ•˜๊ณ  ์žˆ์–ด์š”' }, + { id: 'heart-hands', emoji: '๐Ÿซถ', label: '์—ฐ๊ฒฐ๋˜์–ด ์žˆ์–ด์š”' }, + ], + soundPresets: [ + { id: 'deep-white', label: 'Deep White' }, + { id: 'rain-focus', label: 'Rain Focus' }, + { id: 'cafe-work', label: 'Cafe Work' }, + { id: 'ocean-calm', label: 'Ocean Calm' }, + { id: 'fireplace', label: 'Fireplace' }, + { id: 'silent', label: 'Silent' }, + ], + timerPresets: [ + { id: '25-5', label: '25/5', focusMinutes: 25, breakMinutes: 5 }, + { id: '50-10', label: '50/10', focusMinutes: 50, breakMinutes: 10 }, + { id: '90-20', label: '90/20', focusMinutes: 90, breakMinutes: 20 }, + { id: 'custom', label: '์ปค์Šคํ…€' }, + ], + distractionDumpPlaceholder: ['๋””์ž์ธ QA ์š”์ฒญ ํ™•์ธ', '์„ธ๊ธˆ๊ณ„์‚ฐ์„œ ๋ฐœํ–‰ ๋ฉ”๋ชจ', '์˜คํ›„ ๋ฏธํŒ… ์งˆ๋ฌธ 1๊ฐœ ์ •๋ฆฌ'], + todayStats: [ + { id: 'today-focus', label: '์˜ค๋Š˜ ์ง‘์ค‘ ์‹œ๊ฐ„', value: '2h 40m', delta: '+35m' }, + { id: 'today-cycles', label: '์™„๋ฃŒํ•œ ์‚ฌ์ดํด', value: '5ํšŒ', delta: '+1' }, + { id: 'today-entry', label: '์ž…์žฅ ํšŸ์ˆ˜', value: '3ํšŒ', delta: '์œ ์ง€' }, + ], + weeklyStats: [ + { id: 'week-focus', label: '์ตœ๊ทผ 7์ผ ์ง‘์ค‘ ์‹œ๊ฐ„', value: '14h 20m', delta: '+2h 10m' }, + { id: 'week-best-day', label: '์ตœ๊ณ  ๋ชฐ์ž…์ผ', value: '์ˆ˜์š”์ผ', delta: '3h 30m' }, + { id: 'week-consistency', label: '์—ฐ์† ๋‹ฌ์„ฑ', value: '4์ผ', delta: '+1์ผ' }, + ], + recentThoughts: [ + { + id: 'thought-1', + text: '๋‚ด์ผ ๋ฏธํŒ… ์ „์— ์ œ์•ˆ์„œ ์ฒซ ๋ฌธ๋‹จ๋งŒ ๋‹ค์‹œ ๋‹ค๋“ฌ๊ธฐ', + sceneName: '๋„์„œ๊ด€', + capturedAt: '๋ฐฉ๊ธˆ ์ „', + }, + { + id: 'thought-2', + text: '๊ธฐํš ๋ฌธ์„œ์˜ ํ•ต์‹ฌ ํ๋ฆ„์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ •๋ฆฌํ•ด๋‘๊ธฐ', + sceneName: '๋น„ ์˜ค๋Š” ์ฐฝ๊ฐ€', + capturedAt: '24๋ถ„ ์ „', + }, + { + id: 'thought-3', + text: '์˜คํ›„์— ํ™•์ธํ•  ์ด์Šˆ ๋ฒˆํ˜ธ๋งŒ ๋ฉ”๋ชจํ•˜๊ณ  ์ง€๊ธˆ ์ž‘์—… ๋ณต๊ท€', + sceneName: '์ˆฒ', + capturedAt: '1์‹œ๊ฐ„ ์ „', + }, + { + id: 'thought-4', + text: '๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ๋Š” ์˜ค๋Š˜ 17์‹œ ์ดํ›„์— ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌ', + sceneName: '๋ฒฝ๋‚œ๋กœ', + capturedAt: '์–ด์ œ', + }, + ], + justNow: '๋ฐฉ๊ธˆ ์ „', + }, + scenes: [ + { + id: 'rain-window', + name: '๋น„ ์˜ค๋Š” ์ฐฝ๊ฐ€', + description: '๋น—์†Œ๋ฆฌ ์œ„๋กœ ์Šคํƒ ๋“œ ์กฐ๋ช…์ด ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๋ฒˆ์ง‘๋‹ˆ๋‹ค.', + tags: ['์ €์ž๊ทน', '๊ฐ์„ฑ'], + recommendedSound: 'Rain Focus', + recommendedTime: '๋ฐค', + vibeLabel: '์ž”์ž”ํ•จ', + }, + { + id: 'dawn-cafe', + name: '์ƒˆ๋ฒฝ ์นดํŽ˜', + description: '์ฒซ ์ปคํ”ผ ํ–ฅ์ฒ˜๋Ÿผ ์ž”์ž”ํ•˜๊ณ  ๋”ฐ๋œปํ•œ ์ขŒ์„.', + tags: ['๊ฐ์„ฑ', '๋”ฅ์›Œํฌ'], + recommendedSound: 'Cafe Murmur', + recommendedTime: '์ƒˆ๋ฒฝ', + vibeLabel: 'ํฌ๊ทผํ•จ', + }, + { + id: 'quiet-library', + name: '๋„์„œ๊ด€', + description: '๋„˜๊ธฐ๋Š” ์ข…์ด ์†Œ๋ฆฌ๋งŒ ๋“ค๋ฆฌ๋Š” ์ •๋ˆ๋œ ์ฑ…์ƒ.', + tags: ['์ €์ž๊ทน', '๋”ฅ์›Œํฌ'], + recommendedSound: 'Deep White', + recommendedTime: '์˜คํ›„', + vibeLabel: '๋ชฐ์ž…', + }, + { + id: 'wave-sound', + name: 'ํŒŒ๋„ ์†Œ๋ฆฌ', + description: '์ž”์ž”ํ•œ ํ•ด๋ณ€ ์œ„๋กœ ํ˜ธํก์„ ๊ณ ๋ฅด๋Š” ๊ณต๊ฐ„.', + tags: ['์›€์ง์ž„ ์ ์Œ', '๊ฐ์„ฑ'], + recommendedSound: 'Ocean Breath', + recommendedTime: '๋ฐค', + vibeLabel: '์ฐจ๋ถ„ํ•จ', + }, + { + id: 'green-forest', + name: '์ˆฒ', + description: '๋ฐ”๋žŒ์ด ๋‚˜๋ญ‡์žŽ์„ ์Šค์น˜๋Š” ์†Œ๋ฆฌ๋กœ ๋งˆ์Œ์„ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค.', + tags: ['์ €์ž๊ทน', '์›€์ง์ž„ ์ ์Œ'], + recommendedSound: 'Forest Hush', + recommendedTime: '์˜ค์ „', + vibeLabel: '๋ง‘์Œ', + }, + { + id: 'fireplace', + name: '๋ฒฝ๋‚œ๋กœ', + description: '์ž‘์€ ๋ถˆ๊ฝƒ์ด ์ฃผ๋Š” ๋ฆฌ๋“ฌ์œผ๋กœ ์ง‘์ค‘์„ ๋ถ™์žก์Šต๋‹ˆ๋‹ค.', + tags: ['๊ฐ์„ฑ', '์ €์ž๊ทน'], + recommendedSound: 'Fireplace', + recommendedTime: '๋ฐค', + vibeLabel: '์˜จ๊ธฐ', + }, + { + id: 'city-night', + name: '๋„์‹œ ์•ผ๊ฒฝ', + description: '์œ ๋ฆฌ์ฐฝ ๋„ˆ๋จธ ์•ผ๊ฒฝ์ด ๋ฉ€๋ฆฌ ํ๋ฅด๋Š” ๊ณ ์š”ํ•œ ๋ฐค.', + tags: ['๋”ฅ์›Œํฌ', '๊ฐ์„ฑ'], + recommendedSound: 'Night Lo-fi', + recommendedTime: '์‹ฌ์•ผ', + vibeLabel: '๊ณ ์š”ํ•จ', + }, + { + id: 'snow-mountain', + name: '์„ค์‚ฐ', + description: '์ฐจ๋ถ„ํ•œ ๊ณต๊ธฐ์™€ ์„ ๋ช…ํ•œ ์ˆ˜ํ‰์„ ์ด ๋จธ๋ฆฌ๋ฅผ ๋ง‘๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.', + tags: ['์›€์ง์ž„ ์ ์Œ', '๋”ฅ์›Œํฌ'], + recommendedSound: 'Cold Wind', + recommendedTime: '์ƒˆ๋ฒฝ', + vibeLabel: '์„ ๋ช…ํ•จ', + }, + { + id: 'sun-window', + name: '์ฐฝ๊ฐ€', + description: 'ํ–‡์‚ด์ด ๋“ค์–ด์˜ค๋Š” ๊ฐ„๊ฒฐํ•œ ์ฑ…์ƒ, ๋ถ€๋‹ด ์—†๋Š” ์‹œ์ž‘.', + tags: ['์ €์ž๊ทน', '๋”ฅ์›Œํฌ'], + recommendedSound: 'Soft Daylight', + recommendedTime: '์˜คํ›„', + vibeLabel: '๊ฐ€๋ฒผ์›€', + }, + { + id: 'outer-space', + name: '์šฐ์ฃผ', + description: '๋ณ„๋น›๋งŒ ๋‚จ๊ธด ์–ด๋‘  ์†์—์„œ ๊นŠ๊ฒŒ ์ž ์ˆ˜ํ•ฉ๋‹ˆ๋‹ค.', + tags: ['๋”ฅ์›Œํฌ', '๊ฐ์„ฑ'], + recommendedSound: 'Deep Drone', + recommendedTime: '์‹ฌ์•ผ', + vibeLabel: '๊นŠ์Œ', + }, + ], + modal: { + closeAriaLabel: '๋ชจ๋‹ฌ ๋‹ซ๊ธฐ', + closeButton: '๋‹ซ๊ธฐ', + }, + media: { + manifestLoadFailed: '๋ฏธ๋””์–ด manifest๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์–ด์š”.', + }, + preferences: { + defaultNotificationIntensity: '๊ธฐ๋ณธ', + loadFailed: '์„ค์ •์„ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์–ด์š”.', + saveFailed: '์„ค์ •์„ ์ €์žฅํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + saved: '์ €์žฅ๋จ', + saveFailedLabel: '์ €์žฅ ์‹คํŒจ', + }, + focusSession: { + syncFailed: '์„ธ์…˜ ์—”์ง„๊ณผ ๋™๊ธฐํ™”ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + startFailed: '์„ธ์…˜์„ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + pauseFailed: '์„ธ์…˜์„ ์ผ์‹œ์ •์ง€ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + resumeFailed: '์„ธ์…˜์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + restartPhaseFailed: 'ํ˜„์žฌ ํŽ˜์ด์ฆˆ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + completeFailed: '์„ธ์…˜์„ ์™„๋ฃŒ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + abandonFailed: '์„ธ์…˜์„ ์ข…๋ฃŒํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + }, + space: { + sessionGoal: { + label: '์ด๋ฒˆ 25๋ถ„, ๋”ฑ ํ•œ ๊ฐ€์ง€', + required: '(ํ•„์ˆ˜)', + placeholder: '์˜ˆ: ๊ณ„์•ฝ์„œ 1ํŽ˜์ด์ง€ ์ •๋ฆฌ', + hint: 'ํฌ๊ฒŒ ๋ง๊ณ , ๋ฐ”๋กœ ๋‹ค์Œ ํ•œ ์กฐ๊ฐ.', + }, + setup: { + panelAriaLabel: '์ง‘์ค‘ ์‹œ์ž‘ ํŒจ๋„', + eyebrow: 'Ritual', + title: '์ด๋ฒˆ ํ•œ ์กฐ๊ฐ์„ ์ •ํ•˜๊ณ  ์‹œ์ž‘ํ•ด์š”.', + description: '๋ชฉํ‘œ๋ฅผ ์ •ํ•œ ๋’ค HUD์˜ ์‹œ์ž‘ ๋ฒ„ํŠผ์œผ๋กœ ์‹ค์ œ ์„ธ์…˜์„ ์‹œ์ž‘ํ•ด์š”.', + resumeTitle: '์ง€๋‚œ ํ•œ ์กฐ๊ฐ ์ด์–ด์„œ', + startFresh: '์ƒˆ๋กœ ์‹œ์ž‘', + resumePrepare: '์ด์–ด์„œ ์ค€๋น„', + sceneLabel: '๋ฐฐ๊ฒฝ', + timerLabel: 'ํƒ€์ด๋จธ', + soundLabel: '์‚ฌ์šด๋“œ', + readyHint: '๋ชฉํ‘œ๋ฅผ ์ ์œผ๋ฉด ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์–ด์š”.', + openFocusScreen: '์ง‘์ค‘ ํ™”๋ฉด ์—ด๊ธฐ', + }, + timerHud: { + actions: [ + { id: 'start', label: '์‹œ์ž‘', icon: 'โ–ถ' }, + { id: 'pause', label: '์ผ์‹œ์ •์ง€', icon: 'โธ' }, + { id: 'reset', label: '๋ฆฌ์…‹', icon: 'โ†บ' }, + ], + readyMode: 'Ready', + focusMode: 'Focus', + breakMode: 'Break', + goalFallback: '์ด๋ฒˆ ํ•œ ์กฐ๊ฐ์„ ์„ค์ •ํ•ด ์ฃผ์„ธ์š”.', + goalPrefix: '์ด๋ฒˆ ํ•œ ์กฐ๊ฐ ยท ', + completeButton: '์™„๋ฃŒ', + }, + focusHud: { + goalFallback: '์ง‘์ค‘์„ ์‹œ์ž‘ํ•ด์š”.', + goalToast: (goal: string) => `์ด๋ฒˆ ํ•œ ์กฐ๊ฐ ยท ${goal}`, + restReminder: '5๋ถ„์ด ์ง€๋‚ฌ์–ด์š”. ๋‹ค์Œ ํ•œ ์กฐ๊ฐ์œผ๋กœ ๋Œ์•„์™€์š”.', + }, + goalComplete: { + suggestions: ['๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ 2๊ฐœ ์ฒ˜๋ฆฌ', '๋ฌธ์„œ 1๋ฌธ๋‹จ ๋‹ค๋“ฌ๊ธฐ', '์ด์Šˆ 1๊ฐœ ์ •๋ฆฌ', '๋ฉ”์ผ 2๊ฐœ ํšŒ์‹ '], + placeholderFallback: '๋‹ค์Œ ํ•œ ์กฐ๊ฐ์„ ์ ์–ด๋ณด์„ธ์š”', + placeholderExample: (goal: string) => `์˜ˆ: ${goal}`, + title: '์ข‹์•„์š”. ๋‹ค์Œ ํ•œ ์กฐ๊ฐ์€?', + description: '๋„ˆ๋ฌด ํฌ๊ฒŒ ์žก์ง€ ๋ง๊ณ , ๋ฐ”๋กœ ๋‹ค์Œ ํ•œ ์กฐ๊ฐ๋งŒ.', + closeAriaLabel: '๋‹ซ๊ธฐ', + restButton: '์ž ๊น ์‰ฌ๊ธฐ', + confirmButton: '๋ฐ”๋กœ ๋‹ค์Œ ์กฐ๊ฐ ์‹œ์ž‘', + }, + controlCenter: { + sectionTitles: { + background: 'Background', + time: 'Time', + sound: 'Sound', + packs: 'Packs', + }, + packsDescription: 'ํ™•์žฅ/๊ฐœ์ธํ™”', + recommendation: (soundLabel: string, timerLabel: string) => `์ถ”์ฒœ: ${soundLabel} ยท ${timerLabel}`, + recommendationHint: '์ถ”์ฒœ ์กฐํ•ฉ์€ ์ฐธ๊ณ  ์ •๋ณด๋กœ๋งŒ ์ œ๊ณต๋ผ์š”.', + autoHideTitle: '์ปจํŠธ๋กค ์ž๋™ ์ˆจ๊น€', + autoHideDescription: '์ž…๋ ฅ์ด ์—†์œผ๋ฉด ์ž ์‹œ ํ›„ ํŒจ๋„์„ ๋‹ซ์•„์š”.', + autoHideAriaLabel: '์ปจํŠธ๋กค ์ž๋™ ์ˆจ๊น€', + sideSheetSubtitle: '๋ฐฐ๊ฒฝ ยท ํƒ€์ด๋จธ ยท ์‚ฌ์šด๋“œ๋ฅผ ๊ทธ ์ž๋ฆฌ์—์„œ ๋ฐ”๊ฟ”์š”.', + quickControlsTitle: 'Quick Controls', + }, + toolsDock: { + notesButton: 'Notes', + popoverCloseAria: 'ํŒ์˜ค๋ฒ„ ๋‹ซ๊ธฐ', + planPro: 'PRO', + planNormal: 'Normal', + inboxSaved: '์ธ๋ฐ•์Šค์— ์ €์žฅ๋จ', + undo: '์‹คํ–‰์ทจ์†Œ', + inboxSaveUndone: '์ €์žฅ ์ทจ์†Œ๋จ', + deleted: '์‚ญ์ œ๋จ', + deleteUndone: '์‚ญ์ œ๋ฅผ ์ทจ์†Œํ–ˆ์–ด์š”.', + emptyToClear: '๋น„์šธ ํ•ญ๋ชฉ์ด ์—†์–ด์š”.', + clearedAll: '๋ชจ๋‘ ๋น„์›Œ์ง', + restored: '๋ณต์›ํ–ˆ์–ด์š”.', + normalPlanInfo: 'NORMAL ํ”Œ๋žœ ์‚ฌ์šฉ ์ค‘ ยท ์ž ๊ธˆ ํ•ญ๋ชฉ์—์„œ๋งŒ ์—…๊ทธ๋ ˆ์ด๋“œํ•  ์ˆ˜ ์žˆ์–ด์š”.', + proFeatureLocked: (source: string) => `${source}์€(๋Š”) PRO ๊ธฐ๋Šฅ์ด์—์š”.`, + proFeaturePending: (label: string) => `${label} ์ค€๋น„ ์ค‘(๋”๋ฏธ)`, + purchaseMock: '๊ฒฐ์ œ(๋”๋ฏธ)', + manageSubscriptionMock: '๊ตฌ๋… ๊ด€๋ฆฌ(๋”๋ฏธ)', + restorePurchaseMock: '๊ตฌ๋งค ๋ณต์›(๋”๋ฏธ)', + featureLabels: { + scenePacks: 'Scene Packs', + soundPacks: 'Sound Packs', + profiles: 'Profiles', + }, + utilityPanelTitle: { + 'control-center': 'Quick Controls', + inbox: '์ธ๋ฐ•์Šค', + paywall: 'PRO', + 'manage-plan': 'ํ”Œ๋žœ ๊ด€๋ฆฌ', + }, + }, + quickNotes: { + title: '๋– ์˜ค๋ฅธ ์ƒ๊ฐ์„ ์ž ๊น ์ฃผ์ฐจํ•ด์š”', + placeholder: '๋– ์˜ค๋ฅธ ์ƒ๊ฐ์„ ์ž ๊น ์ฃผ์ฐจโ€ฆ', + submit: '์ €์žฅ', + hint: '๋‚˜์ค‘์— ์ธ๋ฐ•์Šค์—์„œ ์ •๋ฆฌํ•ด์š”.', + }, + quickSound: { + currentSound: 'ํ˜„์žฌ ์‚ฌ์šด๋“œ', + muteAriaLabel: '์Œ์†Œ๊ฑฐ', + unmuteAriaLabel: '์Œ์†Œ๊ฑฐ ํ•ด์ œ', + volumeAriaLabel: '์‚ฌ์šด๋“œ ๋ณผ๋ฅจ', + quickSwitch: '๋น ๋ฅธ ์ „ํ™˜', + }, + soundPresetControls: { + preset: 'Preset', + mixerOpen: 'Mixer ํŽผ์น˜๊ธฐ', + mixerClose: 'Mixer ์ ‘๊ธฐ', + mock: '๋”๋ฏธ', + masterVolume: '๋งˆ์Šคํ„ฐ ๋ณผ๋ฅจ', + mute: '๋ฎคํŠธ', + muteToggleAriaLabel: '๋งˆ์Šคํ„ฐ ๋ฎคํŠธ ํ† ๊ธ€', + trackLabels: { + white: 'White', + rain: 'Rain', + cafe: 'Cafe', + wave: 'Wave', + fan: 'Fan', + }, + }, + inbox: { + empty: '์ง€๊ธˆ์€ ๋น„์–ด ์žˆ์–ด์š”. ์ง‘์ค‘ ์ค‘ ๋– ์˜ค๋ฅธ ์ƒ๊ฐ์„ ์—ฌ๊ธฐ๋กœ ์ฃผ์ฐจํ•  ์ˆ˜ ์žˆ์–ด์š”.', + complete: '์™„๋ฃŒ', + completed: '์™„๋ฃŒ๋จ', + delete: '์‚ญ์ œ', + readOnly: '๋‚˜์ค‘์— ๋ชจ์•„๋ณด๋Š” ์ฝ๊ธฐ ์ „์šฉ ์ธ๋ฐ•์Šค', + clearAll: '๋ชจ๋‘ ๋น„์šฐ๊ธฐ', + clearConfirmTitle: '์ •๋ง ์ธ๋ฐ•์Šค๋ฅผ ๋น„์šธ๊นŒ์š”?', + clearConfirmDescription: '์‹ค์ˆ˜๋ผ๋ฉด ํ† ์ŠคํŠธ์—์„œ ์‹คํ–‰์ทจ์†Œํ•  ์ˆ˜ ์žˆ์–ด์š”.', + clearButton: '๋น„์šฐ๊ธฐ', + openInboxAriaLabel: '์ธ๋ฐ•์Šค ์—ด๊ธฐ', + openInboxTitle: '์ธ๋ฐ•์Šค', + }, + rightRail: { + openQuickControlsAriaLabel: 'Quick Controls ์—ด๊ธฐ', + openQuickControlsTitle: 'Quick Controls', + }, + paywall: { + points: ['ํ”„๋ฆฌ๋ฏธ์—„ Scene Packs', 'ํ™•์žฅ Sound Packs', 'ํ”„๋กœํ•„ ์ €์žฅ / ๋ถˆ๋Ÿฌ์˜ค๊ธฐ'], + title: 'PRO์—์„œ ๋” ๋งŽ์€ ๊ณต๊ฐ„๊ณผ ์‚ฌ์šด๋“œ๋ฅผ ์—ด์–ด๋‘˜ ์ˆ˜ ์žˆ์–ด์š”.', + description: '์ž ๊ธˆ ํ•ญ๋ชฉ์„ ๋ˆ„๋ฅธ ์ˆœ๊ฐ„์—๋งŒ ์—ด๋ฆฌ๋Š” ๋”๋ฏธ ๊ฒฐ์ œ ์‹œํŠธ์ž…๋‹ˆ๋‹ค.', + later: '๋‚˜์ค‘์—', + startPro: 'PRO ์‹œ์ž‘ํ•˜๊ธฐ', + manageTitle: 'PRO ๊ด€๋ฆฌ', + manageDescription: '๊ฒฐ์ œ/๋ณต์›์€ ๋”๋ฏธ ๋™์ž‘์ด๋ฉฐ ์‹ค์ œ ์—ฐ๋™์€ ํ•˜์ง€ ์•Š์•„์š”.', + openSubscription: '๊ตฌ๋… ๊ด€๋ฆฌ ์—ด๊ธฐ', + restorePurchase: '๊ตฌ๋งค ๋ณต์›', + }, + statsPanel: { + description: '์˜ค๋Š˜ ํ๋ฆ„๊ณผ ์ตœ๊ทผ 7์ผ ๋ฆฌ๋“ฌ์„ ๊ฐ€๋ณ๊ฒŒ ํ™•์ธํ•˜์„ธ์š”.', + graphPlaceholder: '๊ทธ๋ž˜ํ”„ ํ”Œ๋ ˆ์ด์Šคํ™€๋”', + }, + settingsPanel: { + reduceMotion: 'Reduce Motion', + reduceMotionDescription: 'ํ™”๋ฉด ์ „ํ™˜์„ ์กฐ๊ธˆ ๋” ์ฐจ๋ถ„ํ•˜๊ฒŒ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.', + background: '๋ฐฐ๊ฒฝ', + backgroundDescription: '๋ชฐ์ž… ์ค‘์—๋„ ๋ฐฐ๊ฒฝ scene์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์š”.', + timerPreset: 'ํƒ€์ด๋จธ ํ”„๋ฆฌ์…‹', + timerPresetDescription: '๊ธฐ๋ณธ ํ”„๋ฆฌ์…‹๋งŒ ๋น ๋ฅด๊ฒŒ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ์–ด์š”.', + defaultPreset: '๊ธฐ๋ณธ ํ”„๋ฆฌ์…‹', + }, + workspace: { + readyToStart: '์ค€๋น„ ์™„๋ฃŒ ยท ์‹œ์ž‘ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ง‘์ค‘์„ ์‹œ์ž‘ํ•ด์š”.', + startFailed: '์„ธ์…˜์„ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”.', + resumeFailed: '์„ธ์…˜์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + abandonFailed: '์„ธ์…˜ ์ข…๋ฃŒ๋ฅผ ์™„๋ฃŒํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + pauseFailed: '์„ธ์…˜์„ ์ผ์‹œ์ •์ง€ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + restartFailed: 'ํ˜„์žฌ ํŽ˜์ด์ฆˆ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + restarted: 'ํ˜„์žฌ ํŽ˜์ด์ฆˆ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ–ˆ์–ด์š”.', + goalCompleteSyncFailed: 'ํ˜„์žฌ ์„ธ์…˜ ์™„๋ฃŒ๋ฅผ ์„œ๋ฒ„์— ๋ฐ˜์˜ํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”.', + nextGoalReady: '๋‹ค์Œ ํ•œ ์กฐ๊ฐ ์ค€๋น„ ์™„๋ฃŒ ยท ์‹œ์ž‘ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ด์–ด๊ฐ€์š”.', + }, + exitHold: { + holdToExitAriaLabel: '๊ธธ๊ฒŒ ๋ˆŒ๋Ÿฌ ๋‚˜๊ฐ€๊ธฐ', + exit: '๋‚˜๊ฐ€๊ธฐ', + }, + }, + soundPlayback: { + loadFailed: '์‚ฌ์šด๋“œ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์–ด์š”.', + browserDeferred: '๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‚ฌ์šด๋“œ ์žฌ์ƒ์„ ๋ณด๋ฅ˜ํ–ˆ์–ด์š”.', + }, + restart30s: { + button: '์ˆจ ๊ณ ๋ฅด๊ธฐ 30์ดˆ', + mode: 'BREATHE', + toast: '์ž ๊น ์ˆจ ๊ณ ๋ฅด๊ณ , ๋‹ค์‹œ ์ฒœ์ฒœํžˆ ์‹œ์ž‘ํ•ด์š”.', + complete: '์ค€๋น„๋์–ด์š”. ์ง‘์ค‘์œผ๋กœ ๋Œ์•„๊ฐ€์š”.', + }, +} as const; diff --git a/src/store/useAuthStore.ts b/src/store/useAuthStore.ts index 7801c06..a2a2e17 100644 --- a/src/store/useAuthStore.ts +++ b/src/store/useAuthStore.ts @@ -1,6 +1,7 @@ import { create } from 'zustand'; import Cookies from 'js-cookie'; import { AuthResponse } from '@/features/auth/types'; +import { REFRESH_TOKEN_COOKIE_KEY, TOKEN_COOKIE_KEY } from '@/features/auth/model/constants'; interface AuthState { accessToken: string | null; @@ -12,10 +13,6 @@ interface AuthState { logout: () => void; } -// ์ฟ ํ‚ค ํ‚ค ์ƒ์ˆ˜ ์ •์˜ -const TOKEN_COOKIE_KEY = 'vr_access_token'; -const REFRESH_TOKEN_COOKIE_KEY = 'vr_refresh_token'; - /** * VibeRoom ์ „์—ญ ์ธ์ฆ(Auth) ์ƒํƒœ ์ €์žฅ์†Œ */