ConfirmDialog 테마 토큰화 + 입력 필드 테마 전환 플래시 수정
- ConfirmDialog 전체를 dialog/icon/ring/danger-btn 토큰으로 이관 - 캐릭터 닉네임 입력의 transition 제거로 테마 전환 시 검은색 플래시 해결 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8e4c7b8c1b
commit
b63ab39977
3 changed files with 97 additions and 18 deletions
|
|
@ -12,8 +12,18 @@ export default function ConfirmDialog({
|
|||
loading = false,
|
||||
}) {
|
||||
const accent = destructive
|
||||
? { ring: 'ring-red-500/20', icon: 'text-red-300', iconBg: 'bg-red-500/10 border-red-500/30' }
|
||||
: { ring: 'ring-emerald-500/20', icon: 'text-emerald-300', iconBg: 'bg-emerald-500/10 border-emerald-500/30' }
|
||||
? {
|
||||
ringColor: 'var(--ring-danger)',
|
||||
iconColor: 'var(--danger-text)',
|
||||
iconBg: 'var(--icon-danger-bg)',
|
||||
iconBorder: 'var(--icon-danger-border)',
|
||||
}
|
||||
: {
|
||||
ringColor: 'var(--ring-info)',
|
||||
iconColor: 'var(--accent-bright)',
|
||||
iconBg: 'var(--icon-info-bg)',
|
||||
iconBorder: 'var(--icon-info-border)',
|
||||
}
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
|
|
@ -24,7 +34,8 @@ export default function ConfirmDialog({
|
|||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.18 }}
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-md"
|
||||
className="fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-md"
|
||||
style={{ background: 'var(--dialog-backdrop)' }}
|
||||
onClick={onClose}
|
||||
>
|
||||
<motion.div
|
||||
|
|
@ -33,48 +44,82 @@ export default function ConfirmDialog({
|
|||
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||
exit={{ opacity: 0, scale: 0.96, y: 4 }}
|
||||
transition={{ duration: 0.2, ease: [0.22, 1, 0.36, 1] }}
|
||||
className={`w-full max-w-md rounded-2xl bg-gradient-to-b from-gray-900 to-gray-950 border border-white/10 shadow-2xl ring-1 ${accent.ring}`}
|
||||
className="w-full max-w-md rounded-2xl border shadow-2xl ring-1"
|
||||
style={{
|
||||
backgroundImage: 'linear-gradient(to bottom, var(--dialog-bg-from), var(--dialog-bg-to))',
|
||||
borderColor: 'var(--dialog-border)',
|
||||
'--tw-ring-color': accent.ringColor,
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="px-7 pt-7 pb-3 flex items-start gap-4">
|
||||
<div className={`shrink-0 w-11 h-11 rounded-xl border flex items-center justify-center ${accent.iconBg}`}>
|
||||
<div
|
||||
className="shrink-0 w-11 h-11 rounded-xl border flex items-center justify-center"
|
||||
style={{ background: accent.iconBg, borderColor: accent.iconBorder, color: accent.iconColor }}
|
||||
>
|
||||
{destructive ? (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" className={accent.icon}>
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 9V13M12 17H12.01M10.29 3.86L1.82 18C1.64 18.31 1.55 18.67 1.55 19.03C1.55 19.4 1.65 19.76 1.83 20.07C2 20.39 2.26 20.65 2.57 20.83C2.88 21.01 3.24 21.1 3.6 21.1H20.47C20.83 21.1 21.19 21.01 21.5 20.83C21.81 20.65 22.07 20.39 22.24 20.07C22.42 19.76 22.52 19.4 22.52 19.03C22.52 18.67 22.43 18.31 22.25 18L13.78 3.86C13.6 3.56 13.35 3.31 13.04 3.14C12.74 2.96 12.4 2.87 12.06 2.87C11.72 2.87 11.38 2.96 11.08 3.14C10.77 3.31 10.52 3.56 10.34 3.86H10.29Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" className={accent.icon}>
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 8V12M12 16H12.01M22 12C22 17.52 17.52 22 12 22C6.48 22 2 17.52 2 12C2 6.48 6.48 2 12 2C17.52 2 22 6.48 22 12Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
<h3 className="flex-1 text-xl font-bold text-white pt-1.5">{title}</h3>
|
||||
<h3
|
||||
className="flex-1 text-xl font-bold pt-1.5"
|
||||
style={{ color: 'var(--text-strong)' }}
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="shrink-0 w-8 h-8 -mt-1 -mr-1 rounded-lg text-gray-500 hover:text-white hover:bg-white/5 transition flex items-center justify-center text-xl leading-none"
|
||||
className="shrink-0 w-8 h-8 -mt-1 -mr-1 rounded-lg hover:bg-[var(--row-hover-bg)] flex items-center justify-center text-xl leading-none"
|
||||
style={{ color: 'var(--text-dim)' }}
|
||||
aria-label="닫기"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div className="px-7 pt-4 pb-7">
|
||||
<p className="text-lg text-gray-300 leading-relaxed whitespace-pre-line">{description}</p>
|
||||
<p
|
||||
className="text-lg leading-relaxed whitespace-pre-line"
|
||||
style={{ color: 'var(--text-muted)' }}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-2 px-7 py-4 border-t border-white/5">
|
||||
<div
|
||||
className="flex gap-2 px-7 py-4 border-t"
|
||||
style={{ borderColor: 'var(--panel-border)' }}
|
||||
>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="flex-1 rounded-lg border border-white/10 bg-white/[0.02] hover:bg-white/[0.06] text-gray-200 px-4 h-11 text-sm font-medium transition"
|
||||
className="flex-1 rounded-lg border px-4 h-11 text-sm font-medium hover:bg-[var(--btn-bg-hover)] hover:border-[var(--btn-border-hover)]"
|
||||
style={{
|
||||
background: 'var(--btn-bg)',
|
||||
borderColor: 'var(--btn-border)',
|
||||
color: 'var(--text-emphasis)',
|
||||
}}
|
||||
>
|
||||
{cancelText}
|
||||
</button>
|
||||
<button
|
||||
onClick={onConfirm}
|
||||
disabled={loading}
|
||||
className={`flex-1 rounded-lg px-4 h-11 text-sm font-semibold transition disabled:opacity-50 ${
|
||||
destructive
|
||||
? 'bg-red-600 hover:bg-red-500 text-white shadow-lg shadow-red-500/20'
|
||||
: 'bg-emerald-600 hover:bg-emerald-500 text-white shadow-lg shadow-emerald-500/20'
|
||||
}`}
|
||||
className="flex-1 rounded-lg px-4 h-11 text-sm font-semibold disabled:opacity-50"
|
||||
style={{
|
||||
background: destructive ? 'var(--btn-danger-bg)' : 'var(--btn-primary-bg)',
|
||||
color: destructive ? 'var(--btn-primary-text)' : 'var(--btn-primary-text)',
|
||||
boxShadow: destructive ? 'var(--btn-danger-shadow)' : 'var(--btn-primary-shadow)',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = destructive ? 'var(--btn-danger-bg-hover)' : 'var(--btn-primary-bg-hover)'
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = destructive ? 'var(--btn-danger-bg)' : 'var(--btn-primary-bg)'
|
||||
}}
|
||||
>
|
||||
{loading ? '처리 중...' : confirmText}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ export default function CharacterPanel({
|
|||
value={name}
|
||||
onChange={(e) => { setName(e.target.value); if (error) setError('') }}
|
||||
placeholder="캐릭터 닉네임 검색"
|
||||
className="w-full rounded-lg border-2 pl-10 pr-3 py-2.5 text-sm outline-none transition focus:border-[var(--input-border-focus)] hover:border-[var(--input-border-hover)]"
|
||||
className="w-full rounded-lg border-2 pl-10 pr-3 py-2.5 text-sm outline-none focus:border-[var(--input-border-focus)] hover:border-[var(--input-border-hover)]"
|
||||
style={{
|
||||
background: 'var(--input-bg)',
|
||||
borderColor: 'var(--input-border)',
|
||||
|
|
|
|||
|
|
@ -123,6 +123,23 @@
|
|||
|
||||
--disabled-opacity: 0.3;
|
||||
--inactive-filter: brightness(0.4);
|
||||
|
||||
--dialog-bg-from: #111827;
|
||||
--dialog-bg-to: #030712;
|
||||
--dialog-border: rgba(255, 255, 255, 0.1);
|
||||
--dialog-backdrop: rgba(0, 0, 0, 0.7);
|
||||
|
||||
--icon-danger-bg: rgba(239, 68, 68, 0.1);
|
||||
--icon-danger-border: rgba(239, 68, 68, 0.3);
|
||||
--icon-info-bg: rgba(16, 185, 129, 0.1);
|
||||
--icon-info-border: rgba(16, 185, 129, 0.3);
|
||||
|
||||
--ring-danger: rgba(239, 68, 68, 0.2);
|
||||
--ring-info: rgba(16, 185, 129, 0.2);
|
||||
|
||||
--btn-danger-bg: #dc2626;
|
||||
--btn-danger-bg-hover: #ef4444;
|
||||
--btn-danger-shadow: 0 4px 14px rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
|
||||
/* 테마 토큰 - light */
|
||||
|
|
@ -242,6 +259,23 @@
|
|||
|
||||
--disabled-opacity: 0.5;
|
||||
--inactive-filter: opacity(0.25);
|
||||
|
||||
--dialog-bg-from: #ffffff;
|
||||
--dialog-bg-to: #ffffff;
|
||||
--dialog-border: rgba(0, 0, 0, 0.1);
|
||||
--dialog-backdrop: rgba(15, 23, 42, 0.45);
|
||||
|
||||
--icon-danger-bg: rgba(220, 38, 38, 0.08);
|
||||
--icon-danger-border: rgba(220, 38, 38, 0.3);
|
||||
--icon-info-bg: rgba(16, 185, 129, 0.08);
|
||||
--icon-info-border: rgba(5, 150, 105, 0.4);
|
||||
|
||||
--ring-danger: rgba(220, 38, 38, 0.15);
|
||||
--ring-info: rgba(16, 185, 129, 0.18);
|
||||
|
||||
--btn-danger-bg: #dc2626;
|
||||
--btn-danger-bg-hover: #b91c1c;
|
||||
--btn-danger-shadow: 0 4px 14px rgba(220, 38, 38, 0.25);
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue