fix(space): recovery 트레이 공통 레이아웃 정리

This commit is contained in:
2026-03-14 18:30:23 +09:00
parent 425943cf89
commit b0fe2887c6
5 changed files with 132 additions and 124 deletions

View File

@@ -13,6 +13,7 @@ import {
HUD_REVEAL_BASE, HUD_REVEAL_BASE,
HUD_REVEAL_COMPLETE, HUD_REVEAL_COMPLETE,
HUD_REVEAL_HIDDEN, HUD_REVEAL_HIDDEN,
HUD_TRAY_CONTENT,
HUD_TEXT_LINK, HUD_TEXT_LINK,
HUD_TEXT_LINK_STRONG, HUD_TEXT_LINK_STRONG,
HUD_TRAY_HAIRLINE, HUD_TRAY_HAIRLINE,
@@ -149,132 +150,134 @@ export const GoalCompleteSheet = ({
<div aria-hidden className={HUD_TRAY_LAYER} /> <div aria-hidden className={HUD_TRAY_LAYER} />
<div aria-hidden className={HUD_TRAY_HAIRLINE} /> <div aria-hidden className={HUD_TRAY_HAIRLINE} />
<header className="relative flex items-start justify-between gap-2"> <div className={HUD_TRAY_CONTENT}>
<div> <header className="flex items-start justify-between gap-2">
<p className="text-[11px] font-medium tracking-[0.08em] text-white/38"> </p> <div>
<h3 className="mt-1 max-w-[22rem] text-[1rem] font-medium tracking-tight text-white/94">{title}</h3> <p className="text-[11px] font-medium tracking-[0.08em] text-white/38"> </p>
<p className="mt-1 max-w-[21rem] text-[12px] leading-[1.55] text-white/56">{description}</p> <h3 className="mt-1 max-w-[22rem] text-[1rem] font-medium tracking-tight text-white/94">{title}</h3>
</div> <p className="mt-1 max-w-[21rem] text-[12px] leading-[1.55] text-white/56">{description}</p>
<button </div>
type="button" <button
onClick={onClose} type="button"
disabled={isSubmitting} onClick={onClose}
className="inline-flex h-8 w-8 items-center justify-center rounded-full border border-white/10 bg-black/14 text-[11px] text-white/72 backdrop-blur-md transition-all hover:bg-black/20 hover:text-white disabled:cursor-not-allowed disabled:border-white/6 disabled:bg-black/10 disabled:text-white/26" disabled={isSubmitting}
aria-label={copy.space.goalComplete.closeAriaLabel} className="inline-flex h-8 w-8 items-center justify-center rounded-full border border-white/10 bg-black/14 text-[11px] text-white/72 backdrop-blur-md transition-all hover:bg-black/20 hover:text-white disabled:cursor-not-allowed disabled:border-white/6 disabled:bg-black/10 disabled:text-white/26"
> aria-label={copy.space.goalComplete.closeAriaLabel}
>
</button>
</header> </button>
</header>
{view === 'choice' ? ( {view === 'choice' ? (
<div className="relative mt-3 space-y-3"> <div className="mt-3 space-y-3">
{trimmedCurrentGoal ? ( {trimmedCurrentGoal ? (
<div className="rounded-[18px] border border-white/8 bg-black/10 px-3.5 py-3"> <div className="rounded-[18px] border border-white/8 bg-black/10 px-3.5 py-3">
<p className="text-[11px] font-medium uppercase tracking-[0.16em] text-white/36"> <p className="text-[11px] font-medium uppercase tracking-[0.16em] text-white/36">
{copy.space.goalComplete.currentGoalLabel} {copy.space.goalComplete.currentGoalLabel}
</p>
<p className="mt-1 truncate text-[14px] text-white/86">{trimmedCurrentGoal}</p>
</div>
) : null}
<footer className="mt-4 space-y-2">
<button
type="button"
onClick={() => setView('next')}
disabled={isSubmitting}
className={cn(HUD_OPTION_ROW, HUD_OPTION_ROW_PRIMARY)}
>
<div className="max-w-[20.5rem]">
<p className="text-[13px] font-semibold tracking-[0.01em] text-white/90">
{copy.space.goalComplete.chooseNextButton}
</p>
<p className="mt-1 text-[12px] leading-[1.55] text-white/48">
{copy.space.goalComplete.chooseNextDescription}
</p> </p>
<p className="mt-1 truncate text-[14px] text-white/86">{trimmedCurrentGoal}</p>
</div> </div>
<span aria-hidden className={HUD_OPTION_CHEVRON}></span> ) : null}
</button>
<button
type="button"
onClick={onRest}
disabled={isSubmitting}
className={cn(HUD_OPTION_ROW, HUD_OPTION_ROW_BREAK)}
>
<div className="max-w-[20.5rem]">
<p className="text-[13px] font-medium tracking-[0.01em] text-white/78">
{copy.space.goalComplete.restButton}
</p>
<p className="mt-1 text-[12px] leading-[1.55] text-emerald-50/56">
{copy.space.goalComplete.restDescription}
</p>
</div>
<span aria-hidden className={cn(HUD_OPTION_CHEVRON, 'text-emerald-100/34 group-hover:text-emerald-100/58')}></span>
</button>
<button
type="button"
onClick={handleFinish}
disabled={isSubmitting}
className={HUD_OPTION_ROW}
>
<div className="max-w-[20.5rem]">
<p className="text-[13px] font-medium tracking-[0.01em] text-white/78">
{submissionMode === 'finish'
? copy.space.goalComplete.finishPending
: copy.space.goalComplete.finishButton}
</p>
<p className="mt-1 text-[12px] leading-[1.55] text-white/44">
{copy.space.goalComplete.finishDescription}
</p>
</div>
<span aria-hidden className={HUD_OPTION_CHEVRON}></span>
</button>
</footer>
</div>
) : (
<form className="relative mt-3 space-y-3" onSubmit={handleSubmit}>
{trimmedCurrentGoal ? (
<div className="rounded-[18px] border border-white/8 bg-black/10 px-3.5 py-3">
<p className="text-[11px] font-medium uppercase tracking-[0.16em] text-white/36">
{copy.space.goalComplete.currentGoalLabel}
</p>
<p className="mt-1 truncate text-[14px] text-white/86">{trimmedCurrentGoal}</p>
</div>
) : null}
<label className="block"> <footer className="mt-4 space-y-2">
<span className="mb-2 block text-[11px] font-medium uppercase tracking-[0.16em] text-white/36"> <button
{copy.space.goalComplete.nextGoalLabel} type="button"
</span> onClick={() => setView('next')}
<input disabled={isSubmitting}
ref={inputRef} className={cn(HUD_OPTION_ROW, HUD_OPTION_ROW_PRIMARY)}
value={draft} >
onChange={(event) => setDraft(event.target.value)} <div className="max-w-[20.5rem]">
placeholder={placeholder} <p className="text-[13px] font-semibold tracking-[0.01em] text-white/90">
className={HUD_FIELD} {copy.space.goalComplete.chooseNextButton}
/> </p>
</label> <p className="mt-1 text-[12px] leading-[1.55] text-white/48">
{copy.space.goalComplete.chooseNextDescription}
</p>
</div>
<span aria-hidden className={HUD_OPTION_CHEVRON}></span>
</button>
<button
type="button"
onClick={onRest}
disabled={isSubmitting}
className={cn(HUD_OPTION_ROW, HUD_OPTION_ROW_BREAK)}
>
<div className="max-w-[20.5rem]">
<p className="text-[13px] font-medium tracking-[0.01em] text-white/78">
{copy.space.goalComplete.restButton}
</p>
<p className="mt-1 text-[12px] leading-[1.55] text-emerald-50/56">
{copy.space.goalComplete.restDescription}
</p>
</div>
<span aria-hidden className={cn(HUD_OPTION_CHEVRON, 'text-emerald-100/34 group-hover:text-emerald-100/58')}></span>
</button>
<button
type="button"
onClick={handleFinish}
disabled={isSubmitting}
className={HUD_OPTION_ROW}
>
<div className="max-w-[20.5rem]">
<p className="text-[13px] font-medium tracking-[0.01em] text-white/78">
{submissionMode === 'finish'
? copy.space.goalComplete.finishPending
: copy.space.goalComplete.finishButton}
</p>
<p className="mt-1 text-[12px] leading-[1.55] text-white/44">
{copy.space.goalComplete.finishDescription}
</p>
</div>
<span aria-hidden className={HUD_OPTION_CHEVRON}></span>
</button>
</footer>
</div>
) : (
<form className="mt-3 space-y-3" onSubmit={handleSubmit}>
{trimmedCurrentGoal ? (
<div className="rounded-[18px] border border-white/8 bg-black/10 px-3.5 py-3">
<p className="text-[11px] font-medium uppercase tracking-[0.16em] text-white/36">
{copy.space.goalComplete.currentGoalLabel}
</p>
<p className="mt-1 truncate text-[14px] text-white/86">{trimmedCurrentGoal}</p>
</div>
) : null}
<footer className="mt-3 flex items-center justify-end gap-2"> <label className="block">
<button <span className="mb-2 block text-[11px] font-medium uppercase tracking-[0.16em] text-white/36">
type="button" {copy.space.goalComplete.nextGoalLabel}
onClick={() => setView('choice')} </span>
disabled={isSubmitting} <input
className={HUD_TEXT_LINK} ref={inputRef}
> value={draft}
{copy.space.goalComplete.backButton} onChange={(event) => setDraft(event.target.value)}
</button> placeholder={placeholder}
<button className={HUD_FIELD}
type="submit" />
disabled={!canConfirm || isSubmitting} </label>
className={HUD_TEXT_LINK_STRONG}
> <footer className="mt-3 flex items-center justify-end gap-2">
{submissionMode === 'next' <button
? copy.space.goalComplete.confirmPending type="button"
: copy.space.goalComplete.confirmButton} onClick={() => setView('choice')}
</button> disabled={isSubmitting}
</footer> className={HUD_TEXT_LINK}
</form> >
)} {copy.space.goalComplete.backButton}
</button>
<button
type="submit"
disabled={!canConfirm || isSubmitting}
className={HUD_TEXT_LINK_STRONG}
>
{submissionMode === 'next'
? copy.space.goalComplete.confirmPending
: copy.space.goalComplete.confirmButton}
</button>
</footer>
</form>
)}
</div>
</section> </section>
</div> </div>
); );

View File

@@ -9,6 +9,7 @@ import {
HUD_REVEAL_BASE, HUD_REVEAL_BASE,
HUD_REVEAL_HIDDEN, HUD_REVEAL_HIDDEN,
HUD_REVEAL_NEXT_BEAT, HUD_REVEAL_NEXT_BEAT,
HUD_TRAY_CONTENT,
HUD_TRAY_HAIRLINE, HUD_TRAY_HAIRLINE,
HUD_TRAY_LAYER, HUD_TRAY_LAYER,
HUD_TRAY_SHELL, HUD_TRAY_SHELL,
@@ -45,7 +46,7 @@ export const NextMicroStepPrompt = ({
<div aria-hidden className={HUD_TRAY_LAYER} /> <div aria-hidden className={HUD_TRAY_LAYER} />
<div aria-hidden className={HUD_TRAY_HAIRLINE} /> <div aria-hidden className={HUD_TRAY_HAIRLINE} />
<div className="relative px-6 py-5"> <div className={HUD_TRAY_CONTENT}>
<p className="text-[11px] font-medium tracking-[0.08em] text-white/42"> <p className="text-[11px] font-medium tracking-[0.08em] text-white/42">
{copy.space.focusHud.microStepPromptEyebrow} {copy.space.focusHud.microStepPromptEyebrow}
</p> </p>

View File

@@ -12,6 +12,7 @@ import {
HUD_REVEAL_BASE, HUD_REVEAL_BASE,
HUD_REVEAL_HIDDEN, HUD_REVEAL_HIDDEN,
HUD_REVEAL_PAUSE, HUD_REVEAL_PAUSE,
HUD_TRAY_CONTENT,
HUD_TRAY_HAIRLINE, HUD_TRAY_HAIRLINE,
HUD_TRAY_LAYER, HUD_TRAY_LAYER,
HUD_TRAY_SHELL, HUD_TRAY_SHELL,
@@ -42,7 +43,7 @@ export const PauseRefocusPrompt = ({
<div aria-hidden className={HUD_TRAY_LAYER} /> <div aria-hidden className={HUD_TRAY_LAYER} />
<div aria-hidden className={HUD_TRAY_HAIRLINE} /> <div aria-hidden className={HUD_TRAY_HAIRLINE} />
<div className="relative px-6 py-5 md:px-6 md:py-5"> <div className={HUD_TRAY_CONTENT}>
<p className={HUD_PAUSE_EYEBROW}> <p className={HUD_PAUSE_EYEBROW}>
{copy.space.focusHud.pausePromptEyebrow} {copy.space.focusHud.pausePromptEyebrow}
</p> </p>

View File

@@ -13,6 +13,7 @@ import {
HUD_REVEAL_RETURN_FOCUS, HUD_REVEAL_RETURN_FOCUS,
HUD_RETURN_BODY, HUD_RETURN_BODY,
HUD_RETURN_TITLE, HUD_RETURN_TITLE,
HUD_TRAY_CONTENT,
HUD_TRAY_HAIRLINE_BREAK, HUD_TRAY_HAIRLINE_BREAK,
HUD_TRAY_HAIRLINE, HUD_TRAY_HAIRLINE,
HUD_TRAY_LAYER_BREAK, HUD_TRAY_LAYER_BREAK,
@@ -58,7 +59,7 @@ export const ReturnPrompt = ({
<div aria-hidden className={isBreakReturn ? HUD_TRAY_LAYER_BREAK : HUD_TRAY_LAYER} /> <div aria-hidden className={isBreakReturn ? HUD_TRAY_LAYER_BREAK : HUD_TRAY_LAYER} />
<div aria-hidden className={isBreakReturn ? HUD_TRAY_HAIRLINE_BREAK : HUD_TRAY_HAIRLINE} /> <div aria-hidden className={isBreakReturn ? HUD_TRAY_HAIRLINE_BREAK : HUD_TRAY_HAIRLINE} />
<div className="relative px-6 py-5"> <div className={HUD_TRAY_CONTENT}>
<p className={cn( <p className={cn(
'text-[11px] font-medium tracking-[0.12em]', 'text-[11px] font-medium tracking-[0.12em]',
isBreakReturn ? 'text-emerald-100/54' : 'text-white/42', isBreakReturn ? 'text-emerald-100/54' : 'text-white/42',

View File

@@ -14,6 +14,8 @@ export const HUD_TRAY_HAIRLINE = 'pointer-events-none absolute inset-x-0 top-0 h
export const HUD_TRAY_HAIRLINE_BREAK = 'pointer-events-none absolute inset-x-0 top-0 h-px bg-emerald-200/18'; export const HUD_TRAY_HAIRLINE_BREAK = 'pointer-events-none absolute inset-x-0 top-0 h-px bg-emerald-200/18';
export const HUD_TRAY_CONTENT = 'relative px-6 py-5';
export const HUD_REVEAL_BASE = export const HUD_REVEAL_BASE =
'pointer-events-none w-full origin-top-left overflow-hidden transition-[max-height,opacity,transform] motion-reduce:transition-none'; 'pointer-events-none w-full origin-top-left overflow-hidden transition-[max-height,opacity,transform] motion-reduce:transition-none';