fix: i18n의 타입 수정

This commit is contained in:
2026-02-14 21:55:54 +09:00
parent 82e2c08262
commit 1ccb9e517a
3 changed files with 58 additions and 37 deletions

View File

@@ -1,7 +1,7 @@
import { FLIGHT_STARFIELD_TUNING } from '@/shared/config/starfield'; import { FLIGHT_STARFIELD_TUNING } from "@/shared/config/starfield";
import { clamp, randomInRange } from '@/shared/lib/math/number'; import { clamp, randomInRange } from "@/shared/lib/math/number";
import { FlightStar } from '@/features/flight-starfield/model/types'; import { FlightStar } from "@/features/flight-starfield/model/types";
export const getFlightStarCount = (width: number, height: number) => { export const getFlightStarCount = (width: number, height: number) => {
const isMobile = width < FLIGHT_STARFIELD_TUNING.mobileBreakpoint; const isMobile = width < FLIGHT_STARFIELD_TUNING.mobileBreakpoint;
@@ -11,7 +11,9 @@ export const getFlightStarCount = (width: number, height: number) => {
const max = isMobile const max = isMobile
? FLIGHT_STARFIELD_TUNING.starCount.mobile.max ? FLIGHT_STARFIELD_TUNING.starCount.mobile.max
: FLIGHT_STARFIELD_TUNING.starCount.desktop.max; : FLIGHT_STARFIELD_TUNING.starCount.desktop.max;
const byArea = Math.round((width * height) / FLIGHT_STARFIELD_TUNING.densityDivisor); const byArea = Math.round(
(width * height) / FLIGHT_STARFIELD_TUNING.densityDivisor,
);
return clamp(byArea, min, max); return clamp(byArea, min, max);
}; };
@@ -51,7 +53,8 @@ const createFlightSpeed = () => {
}; };
const createFlightVisualTier = () => { const createFlightVisualTier = () => {
const highlight = Math.random() < FLIGHT_STARFIELD_TUNING.radius.highlightChance; const highlight =
Math.random() < FLIGHT_STARFIELD_TUNING.radius.highlightChance;
const tailRoll = Math.random(); const tailRoll = Math.random();
const tailLength = const tailLength =
tailRoll < FLIGHT_STARFIELD_TUNING.tail.pointChance tailRoll < FLIGHT_STARFIELD_TUNING.tail.pointChance
@@ -95,7 +98,8 @@ const createFlightVisualTier = () => {
const createFlightSpawnRadius = (width: number, height: number) => { const createFlightSpawnRadius = (width: number, height: number) => {
const roll = Math.random(); const roll = Math.random();
const maxWideRadius = Math.min( const maxWideRadius = Math.min(
Math.max(width, height) * FLIGHT_STARFIELD_TUNING.spawnRadius.wideRange.maxScaleOfViewport, Math.max(width, height) *
FLIGHT_STARFIELD_TUNING.spawnRadius.wideRange.maxScaleOfViewport,
FLIGHT_STARFIELD_TUNING.spawnRadius.wideRange.maxAbsolute, FLIGHT_STARFIELD_TUNING.spawnRadius.wideRange.maxAbsolute,
); );
const ringOuter = Math.min( const ringOuter = Math.min(

View File

@@ -1,17 +1,20 @@
'use client'; "use client";
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from "react";
import { projectFlightStar, createVanishingPoint } from '@/features/flight-starfield/lib/projection'; import {
createVanishingPoint,
projectFlightStar,
} from "@/features/flight-starfield/lib/projection";
import { import {
createFlightStar, createFlightStar,
createFlightVanishXJitter, createFlightVanishXJitter,
getFlightStarCount, getFlightStarCount,
shouldRecycleFlightStar, shouldRecycleFlightStar,
} from '@/features/flight-starfield/model/starfieldModel'; } from "@/features/flight-starfield/model/starfieldModel";
import { FlightStar } from '@/features/flight-starfield/model/types'; import { FlightStar } from "@/features/flight-starfield/model/types";
import { clamp } from '@/shared/lib/math/number'; import { clamp } from "@/shared/lib/math/number";
import { getPrefersReducedMotionMediaQuery } from '@/shared/lib/motion/prefersReducedMotion'; import { getPrefersReducedMotionMediaQuery } from "@/shared/lib/motion/prefersReducedMotion";
export function FlightStarfieldCanvas({ export function FlightStarfieldCanvas({
vanishYOffset = -68, vanishYOffset = -68,
@@ -30,7 +33,7 @@ export function FlightStarfieldCanvas({
const canvas = canvasRef.current; const canvas = canvasRef.current;
if (!canvas) return; if (!canvas) return;
const context = canvas.getContext('2d'); const context = canvas.getContext("2d");
if (!context) return; if (!context) return;
let width = window.innerWidth; let width = window.innerWidth;
@@ -102,7 +105,7 @@ export function FlightStarfieldCanvas({
if (star.tailLength < 1 || movementLength < 0.001) { if (star.tailLength < 1 || movementLength < 0.001) {
context.globalAlpha = visibleAlpha; context.globalAlpha = visibleAlpha;
context.fillStyle = '#f8fbff'; context.fillStyle = "#f8fbff";
context.beginPath(); context.beginPath();
context.arc(toX, toY, star.radius, 0, Math.PI * 2); context.arc(toX, toY, star.radius, 0, Math.PI * 2);
context.fill(); context.fill();
@@ -116,7 +119,7 @@ export function FlightStarfieldCanvas({
const tailY = toY - directionY * star.tailLength; const tailY = toY - directionY * star.tailLength;
const gradient = context.createLinearGradient(tailX, tailY, toX, toY); const gradient = context.createLinearGradient(tailX, tailY, toX, toY);
gradient.addColorStop(0, 'rgba(248, 251, 255, 0)'); gradient.addColorStop(0, "rgba(248, 251, 255, 0)");
gradient.addColorStop(1, `rgba(248, 251, 255, ${visibleAlpha})`); gradient.addColorStop(1, `rgba(248, 251, 255, ${visibleAlpha})`);
context.strokeStyle = gradient; context.strokeStyle = gradient;
@@ -127,9 +130,15 @@ export function FlightStarfieldCanvas({
context.stroke(); context.stroke();
context.globalAlpha = Math.min(1, visibleAlpha + 0.08); context.globalAlpha = Math.min(1, visibleAlpha + 0.08);
context.fillStyle = '#f8fbff'; context.fillStyle = "#f8fbff";
context.beginPath(); context.beginPath();
context.arc(toX, toY, clamp(star.radius * 0.72, 0.6, 1.45), 0, Math.PI * 2); context.arc(
toX,
toY,
clamp(star.radius * 0.72, 0.6, 1.45),
0,
Math.PI * 2,
);
context.fill(); context.fill();
context.globalAlpha = 1; context.globalAlpha = 1;
}; };
@@ -144,9 +153,9 @@ export function FlightStarfieldCanvas({
vp.y, vp.y,
centerProtectRadius * 1.35, centerProtectRadius * 1.35,
); );
veil.addColorStop(0, 'rgba(160, 185, 235, 0.08)'); veil.addColorStop(0, "rgba(160, 185, 235, 0.08)");
veil.addColorStop(0.55, 'rgba(90, 114, 170, 0.03)'); veil.addColorStop(0.55, "rgba(90, 114, 170, 0.03)");
veil.addColorStop(1, 'rgba(0, 0, 0, 0)'); veil.addColorStop(1, "rgba(0, 0, 0, 0)");
context.fillStyle = veil; context.fillStyle = veil;
context.fillRect(0, 0, width, height); context.fillRect(0, 0, width, height);
@@ -161,14 +170,14 @@ export function FlightStarfieldCanvas({
height / 2, height / 2,
Math.max(width, height) * 0.95, Math.max(width, height) * 0.95,
); );
vignette.addColorStop(0, 'rgba(0, 0, 0, 0)'); vignette.addColorStop(0, "rgba(0, 0, 0, 0)");
vignette.addColorStop(1, 'rgba(0, 0, 0, 0.82)'); vignette.addColorStop(1, "rgba(0, 0, 0, 0.82)");
context.fillStyle = vignette; context.fillStyle = vignette;
context.fillRect(0, 0, width, height); context.fillRect(0, 0, width, height);
}; };
const drawFrame = (moveStars: boolean) => { const drawFrame = (moveStars: boolean) => {
context.fillStyle = 'rgba(2, 5, 10, 0.3)'; context.fillStyle = "rgba(2, 5, 10, 0.3)";
context.fillRect(0, 0, width, height); context.fillRect(0, 0, width, height);
drawCenterVeil(); drawCenterVeil();
@@ -254,8 +263,8 @@ export function FlightStarfieldCanvas({
} }
}; };
window.addEventListener('resize', handleResize); window.addEventListener("resize", handleResize);
motionQuery.addEventListener('change', handleMotionChange); motionQuery.addEventListener("change", handleMotionChange);
if (prefersReducedMotion || isPaused) { if (prefersReducedMotion || isPaused) {
renderStatic(); renderStatic();
@@ -264,11 +273,16 @@ export function FlightStarfieldCanvas({
} }
return () => { return () => {
window.removeEventListener('resize', handleResize); window.removeEventListener("resize", handleResize);
motionQuery.removeEventListener('change', handleMotionChange); motionQuery.removeEventListener("change", handleMotionChange);
stopAnimation(); stopAnimation();
}; };
}, [vanishYOffset, centerProtectRadius, isPaused]); }, [vanishYOffset, centerProtectRadius, isPaused]);
return <canvas ref={canvasRef} className="fixed inset-0 z-0 bg-black pointer-events-none" />; return (
<canvas
ref={canvasRef}
className="fixed inset-0 z-0 bg-black pointer-events-none"
/>
);
} }

View File

@@ -82,11 +82,12 @@ const enMessages = {
"status.reoriented": "Reoriented", "status.reoriented": "Reoriented",
"status.aborted": "Aborted Early", "status.aborted": "Aborted Early",
"status.in_progress": "In Progress", "status.in_progress": "In Progress",
} as const; } satisfies Record<string, string>;
type I18nMessages = typeof enMessages; type MessageKey = keyof typeof enMessages;
type I18nMessages = Record<MessageKey, string>;
const koMessages: I18nMessages = { const koMessages = {
"layout.nav.log": "항해일지", "layout.nav.log": "항해일지",
"layout.nav.settings": "설정", "layout.nav.settings": "설정",
"layout.nav.language": "언어", "layout.nav.language": "언어",
@@ -155,9 +156,9 @@ const koMessages: I18nMessages = {
"status.reoriented": "🧭 방향 재설정", "status.reoriented": "🧭 방향 재설정",
"status.aborted": "🚨 조기 귀환", "status.aborted": "🚨 조기 귀환",
"status.in_progress": "진행 중", "status.in_progress": "진행 중",
}; } satisfies I18nMessages;
const jaMessages: I18nMessages = { const jaMessages = {
"layout.nav.log": "航海ログ", "layout.nav.log": "航海ログ",
"layout.nav.settings": "設定", "layout.nav.settings": "設定",
"layout.nav.language": "言語", "layout.nav.language": "言語",
@@ -226,15 +227,17 @@ const jaMessages: I18nMessages = {
"status.reoriented": "🧭 方針再設定", "status.reoriented": "🧭 方針再設定",
"status.aborted": "🚨 早期帰還", "status.aborted": "🚨 早期帰還",
"status.in_progress": "進行中", "status.in_progress": "進行中",
}; } satisfies I18nMessages;
const normalizedEnMessages: I18nMessages = enMessages;
export const I18N_MESSAGES: Record<Locale, I18nMessages> = { export const I18N_MESSAGES: Record<Locale, I18nMessages> = {
ko: koMessages, ko: koMessages,
en: enMessages, en: normalizedEnMessages,
ja: jaMessages, ja: jaMessages,
}; };
export type I18nKey = keyof I18nMessages; export type I18nKey = MessageKey;
export type TranslationParams = Record<string, string | number>; export type TranslationParams = Record<string, string | number>;