29fd0c9a0f
Aggressive cleanup of 359 exports across 153 files identified as having zero importers outside their declaring module: - 105 symbols deleted entirely (no internal uses either) - 254 symbols un-exported (still referenced file-locally; dropped the `export` keyword to shrink the public surface) - ~70 cascade cleanups of locals that became dead once their sole consumer was removed Notable shrinkage: - src/hooks/useShakespeare.ts: 626 \u2192 22 lines (unwired AI chat surface; only the ChatMessage type is consumed) - src/hooks/useTrending.ts: only useEventStats survives; trending feed hooks were never wired up - src/hooks/useTrustedCountryStats.ts: dead type re-exports removed - src/lib/bitcoin.ts: PSBT helpers \u2014 unused wallet feature scaffolding - src/lib/communityUtils.ts: unused NIP-72 moderation helpers - src/lib/extraKinds.ts, src/lib/colorUtils.ts: unused helpers - src/lib/logger.ts: bare debug/info/warn/error exports dropped; consumers use the `logger` object - src/lib/aiChatSystemPrompt.ts: trimmed to the DEFAULT_SYSTEM_PROMPT_TEMPLATE constant - src/components/music/MusicTrackRow.tsx: dead row component removed; only the skeleton is consumed src/hooks/useNostr.ts (intentional decoy) and src/i18n.ts (side-effect import) were preserved per their respective contracts.
87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
import { useState, type ReactNode } from 'react';
|
|
import { Loader2 } from 'lucide-react';
|
|
|
|
/**
|
|
* Toast description content for the signer nudge toast.
|
|
*
|
|
* On Android, includes an "Approve in signer" link that opens the signer via
|
|
* the `nostrsigner:` URI scheme (keeps the WebSocket alive), plus a
|
|
* Skip/Cancel button. On desktop, shows a description with a Skip button.
|
|
*/
|
|
export function NudgeToastContent({
|
|
description,
|
|
android,
|
|
relayOk,
|
|
onCancel,
|
|
}: {
|
|
description: string;
|
|
android: boolean;
|
|
relayOk: boolean;
|
|
onCancel: () => void;
|
|
}): ReactNode {
|
|
return (
|
|
<span>
|
|
<span className="block text-sm opacity-80">{description}</span>
|
|
{android && relayOk ? (
|
|
<AndroidApproveRow onCancel={onCancel} />
|
|
) : (
|
|
<span className="block mt-1.5">
|
|
<SkipButton onClick={onCancel} />
|
|
</span>
|
|
)}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Internal components
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function AndroidApproveRow({ onCancel }: { onCancel: () => void }) {
|
|
const [waiting, setWaiting] = useState(false);
|
|
|
|
return (
|
|
<span className="flex items-center gap-3 mt-2">
|
|
{waiting ? (
|
|
<span className="text-sm opacity-80 inline-flex items-center gap-1.5">
|
|
<Loader2 className="size-4 animate-spin" />
|
|
Waiting for signer...
|
|
</span>
|
|
) : (
|
|
<a
|
|
href="nostrsigner:"
|
|
className="text-sm font-semibold border border-current rounded px-3 py-1.5 no-underline inline-flex items-center gap-1.5 min-h-[44px]"
|
|
onClick={() => {
|
|
setWaiting(true);
|
|
}}
|
|
>
|
|
Approve in signer
|
|
</a>
|
|
)}
|
|
{waiting ? (
|
|
<button
|
|
type="button"
|
|
onClick={onCancel}
|
|
className="text-sm font-semibold border border-current rounded px-3 py-1.5 min-h-[44px]"
|
|
>
|
|
Cancel
|
|
</button>
|
|
) : (
|
|
<SkipButton onClick={onCancel} />
|
|
)}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function SkipButton({ onClick }: { onClick: () => void }) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
onClick={onClick}
|
|
className="text-sm bg-transparent border-none p-0 cursor-pointer opacity-80 underline underline-offset-2 min-h-[44px] inline-flex items-center"
|
|
>
|
|
Skip
|
|
</button>
|
|
);
|
|
}
|