Skip to content

Commit 555b231

Browse files
committed
emergency-withdraw: mobile layout fixes + vault-load failure handling
Timestamps and inline `code` no longer break mid-token or overflow the card on narrow screens. A failed vault read now shows a retry card instead of a dead end, and a successful connect scrolls to the vault section on mobile.
1 parent c3de3be commit 555b231

2 files changed

Lines changed: 58 additions & 2 deletions

File tree

emergency-withdraw/src/App.tsx

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function renderRich(s: string, codeClass = 'text-cyan-300'): ReactNode {
121121
return s.split(/(`[^`]+`|\*[^*]+\*)/g).map((part, i) => {
122122
if (part.length > 1 && part.startsWith('`') && part.endsWith('`')) {
123123
return (
124-
<code key={i} className={`font-mono ${codeClass}`}>
124+
<code key={i} className={`font-mono break-words ${codeClass}`}>
125125
{part.slice(1, -1)}
126126
</code>
127127
)
@@ -245,16 +245,22 @@ function InfoRow({
245245
value,
246246
tone = 'default',
247247
mono = true,
248+
breakAll = true,
248249
}: {
249250
label: string
250251
value: ReactNode
251252
tone?: Tone
252253
mono?: boolean
254+
breakAll?: boolean
253255
}) {
254256
return (
255257
<div className="flex items-baseline justify-between gap-4 text-sm">
256258
<span className="text-slate-400 shrink-0">{label}</span>
257-
<span className={`text-right break-all ${mono ? 'font-mono' : ''} ${TONE_TEXT[tone]}`}>
259+
<span
260+
className={`text-right ${breakAll ? 'break-all' : 'break-words'} ${
261+
mono ? 'font-mono' : ''
262+
} ${TONE_TEXT[tone]}`}
263+
>
258264
{value}
259265
</span>
260266
</div>
@@ -289,6 +295,7 @@ function SectionCard({
289295
accent = 'cyan',
290296
action,
291297
danger,
298+
id,
292299
children,
293300
}: {
294301
title: string
@@ -297,6 +304,7 @@ function SectionCard({
297304
accent?: 'cyan' | 'emerald' | 'amber' | 'slate'
298305
action?: ReactNode
299306
danger?: boolean
307+
id?: string
300308
children: ReactNode
301309
}) {
302310
const text = {
@@ -313,6 +321,7 @@ function SectionCard({
313321
}[accent]
314322
return (
315323
<section
324+
id={id}
316325
className={`glass-card glow-border rounded-2xl sm:rounded-3xl p-5 sm:p-6 md:p-7 space-y-4 sm:space-y-5 ${
317326
danger ? 'danger' : ''
318327
}`}
@@ -365,6 +374,7 @@ export default function App() {
365374
const [txHash, setTxHash] = useState('')
366375
const [sharesInput, setSharesInput] = useState('')
367376
const [sunsetConfirmOpen, setSunsetConfirmOpen] = useState(false)
377+
const justConnectedRef = useRef(false)
368378

369379
// ── Bootstrap: load config + wallet list ──
370380
useEffect(() => {
@@ -384,6 +394,17 @@ export default function App() {
384394
}
385395
}, [])
386396

397+
// After a fresh connect, scroll the vault section into view on mobile.
398+
useEffect(() => {
399+
if (!vault || !justConnectedRef.current) return
400+
justConnectedRef.current = false
401+
if (typeof window !== 'undefined' && window.innerWidth < 640) {
402+
document
403+
.getElementById('vault-section')
404+
?.scrollIntoView({ behavior: 'smooth', block: 'start' })
405+
}
406+
}, [vault])
407+
387408
// ── Connect flow ──
388409
async function handleConnect() {
389410
setStatus(null)
@@ -428,6 +449,7 @@ export default function App() {
428449
setLucid(ld)
429450
setWalletAddr(addr)
430451
setNetworkResolved(resolvedNet)
452+
justConnectedRef.current = true
431453
setStatus({ kind: 'ok', text: t('st.connected') })
432454
await loadOnChainState(ld, resolvedNet)
433455
} catch (e) {
@@ -723,9 +745,31 @@ export default function App() {
723745
</div>
724746
)}
725747

748+
{/* ── Vault load failed (connected but state unreadable) ── */}
749+
{lucid && !vault && (
750+
<SectionCard
751+
title={t('vault.loadFailedTitle')}
752+
eyebrow={t('vault.eyebrow')}
753+
iconPath={ICON.alert}
754+
accent="amber"
755+
>
756+
<p className="text-xs sm:text-sm text-slate-400 leading-relaxed">
757+
{t('vault.loadFailedBody')}
758+
</p>
759+
<button
760+
onClick={handleRefresh}
761+
disabled={busy}
762+
className="btn-shine w-full bg-gradient-to-r from-amber-500 to-cyan-500 hover:from-amber-400 hover:to-cyan-400 active:scale-[0.99] disabled:from-slate-600 disabled:to-slate-600 disabled:cursor-not-allowed text-slate-950 font-bold py-3 rounded-xl transition-all"
763+
>
764+
{busy ? t('wd.btnBusy') : t('vault.retry')}
765+
</button>
766+
</SectionCard>
767+
)}
768+
726769
{/* ── Vault State ── */}
727770
{lucid && vault && (
728771
<SectionCard
772+
id="vault-section"
729773
title={t('vault.title')}
730774
eyebrow={t('vault.eyebrow')}
731775
iconPath={ICON.vault}
@@ -783,10 +827,12 @@ export default function App() {
783827
<InfoRow
784828
label={t('vault.lastCompound')}
785829
value={fmtTime(vault.lastCompoundTime, t('vault.never'))}
830+
breakAll={false}
786831
/>
787832
<InfoRow
788833
label={t('vault.lastRealloc')}
789834
value={fmtTime(vault.lastReallocTime, t('vault.never'))}
835+
breakAll={false}
790836
/>
791837
</DataPanel>
792838

@@ -945,6 +991,7 @@ export default function App() {
945991
<InfoRow
946992
label={t('sunset.lastActivity')}
947993
value={fmtTime(sunset.lastActivityMs, t('vault.never'))}
994+
breakAll={false}
948995
/>
949996
<InfoRow
950997
label={t('sunset.daysSince')}

emergency-withdraw/src/i18n.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ const translations: Record<Lang, Translations> = {
9999
liqwid: 'Liqwid positions',
100100
never: 'never',
101101
na: 'n/a',
102+
loadFailedTitle: 'Could not load the vault',
103+
loadFailedBody: 'Connected — but the vault state could not be read from Cardano. This is usually a temporary Blockfrost hiccup or a stale deploy-state. Check the message above, then retry.',
104+
retry: 'Retry',
102105
},
103106
wd: {
104107
step: 'Step 2',
@@ -274,6 +277,9 @@ const translations: Record<Lang, Translations> = {
274277
liqwid: 'Liqwid 部位',
275278
never: '從未',
276279
na: '不適用',
280+
loadFailedTitle: '無法載入金庫',
281+
loadFailedBody: '已連線,但無法從 Cardano 讀取金庫狀態。通常是 Blockfrost 暫時性問題,或部署狀態過期。請參考上方訊息後再重試。',
282+
retry: '重試',
277283
},
278284
wd: {
279285
step: '步驟 2',
@@ -449,6 +455,9 @@ const translations: Record<Lang, Translations> = {
449455
liqwid: 'Liqwid ポジション',
450456
never: 'なし',
451457
na: '該当なし',
458+
loadFailedTitle: 'ヴォールトを読み込めませんでした',
459+
loadFailedBody: '接続済みですが、Cardano からヴォールト状態を読み取れませんでした。多くは Blockfrost の一時的な不具合か、デプロイ状態が古いことが原因です。上のメッセージを確認してから再試行してください。',
460+
retry: '再試行',
452461
},
453462
wd: {
454463
step: 'ステップ 2',

0 commit comments

Comments
 (0)