chore: format

This commit is contained in:
codytseng 2026-01-22 22:28:07 +08:00
parent 4bd4141b54
commit e490407dd5
225 changed files with 924 additions and 844 deletions

View file

@ -2,3 +2,4 @@ singleQuote: true
semi: false semi: false
printWidth: 100 printWidth: 100
trailingComma: none trailingComma: none
plugins: [prettier-plugin-tailwindcss]

80
package-lock.json generated
View file

@ -95,6 +95,7 @@
"globals": "^15.13.0", "globals": "^15.13.0",
"postcss": "^8.4.49", "postcss": "^8.4.49",
"prettier": "3.4.2", "prettier": "3.4.2",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"typescript-eslint": "^8.18.1", "typescript-eslint": "^8.18.1",
@ -10392,6 +10393,85 @@
"url": "https://github.com/prettier/prettier?sponsor=1" "url": "https://github.com/prettier/prettier?sponsor=1"
} }
}, },
"node_modules/prettier-plugin-tailwindcss": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz",
"integrity": "sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20.19"
},
"peerDependencies": {
"@ianvs/prettier-plugin-sort-imports": "*",
"@prettier/plugin-hermes": "*",
"@prettier/plugin-oxc": "*",
"@prettier/plugin-pug": "*",
"@shopify/prettier-plugin-liquid": "*",
"@trivago/prettier-plugin-sort-imports": "*",
"@zackad/prettier-plugin-twig": "*",
"prettier": "^3.0",
"prettier-plugin-astro": "*",
"prettier-plugin-css-order": "*",
"prettier-plugin-jsdoc": "*",
"prettier-plugin-marko": "*",
"prettier-plugin-multiline-arrays": "*",
"prettier-plugin-organize-attributes": "*",
"prettier-plugin-organize-imports": "*",
"prettier-plugin-sort-imports": "*",
"prettier-plugin-svelte": "*"
},
"peerDependenciesMeta": {
"@ianvs/prettier-plugin-sort-imports": {
"optional": true
},
"@prettier/plugin-hermes": {
"optional": true
},
"@prettier/plugin-oxc": {
"optional": true
},
"@prettier/plugin-pug": {
"optional": true
},
"@shopify/prettier-plugin-liquid": {
"optional": true
},
"@trivago/prettier-plugin-sort-imports": {
"optional": true
},
"@zackad/prettier-plugin-twig": {
"optional": true
},
"prettier-plugin-astro": {
"optional": true
},
"prettier-plugin-css-order": {
"optional": true
},
"prettier-plugin-jsdoc": {
"optional": true
},
"prettier-plugin-marko": {
"optional": true
},
"prettier-plugin-multiline-arrays": {
"optional": true
},
"prettier-plugin-organize-attributes": {
"optional": true
},
"prettier-plugin-organize-imports": {
"optional": true
},
"prettier-plugin-sort-imports": {
"optional": true
},
"prettier-plugin-svelte": {
"optional": true
}
}
},
"node_modules/pretty-bytes": { "node_modules/pretty-bytes": {
"version": "6.1.1", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz",

View file

@ -105,10 +105,11 @@
"globals": "^15.13.0", "globals": "^15.13.0",
"postcss": "^8.4.49", "postcss": "^8.4.49",
"prettier": "3.4.2", "prettier": "3.4.2",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"typescript-eslint": "^8.18.1", "typescript-eslint": "^8.18.1",
"vite": "^6.0.3", "vite": "^6.0.3",
"vite-plugin-pwa": "^0.21.1" "vite-plugin-pwa": "^0.21.1"
} }
} }

View file

@ -339,11 +339,11 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
> >
<CurrentRelaysProvider> <CurrentRelaysProvider>
<NotificationProvider> <NotificationProvider>
<div className="flex lg:justify-around w-full"> <div className="flex w-full lg:justify-around">
<div className="sticky top-0 lg:w-full flex justify-end self-start h-[var(--vh)]"> <div className="sticky top-0 flex h-[var(--vh)] justify-end self-start lg:w-full">
<Sidebar /> <Sidebar />
</div> </div>
<div className="flex-1 w-0 bg-background border-x lg:flex-auto lg:w-[640px] lg:shrink-0"> <div className="w-0 flex-1 border-x bg-background lg:w-[640px] lg:flex-auto lg:shrink-0">
{!!secondaryStack.length && {!!secondaryStack.length &&
secondaryStack.map((item, index) => ( secondaryStack.map((item, index) => (
<div <div
@ -369,10 +369,10 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
</div> </div>
))} ))}
</div> </div>
<div className="hidden lg:w-full lg:block" /> <div className="hidden lg:block lg:w-full" />
</div> </div>
<TooManyRelaysAlertDialog /> <TooManyRelaysAlertDialog />
<BackgroundAudio className="fixed bottom-20 right-0 z-50 w-80 rounded-l-full rounded-r-none overflow-hidden shadow-lg border" /> <BackgroundAudio className="fixed bottom-20 right-0 z-50 w-80 overflow-hidden rounded-l-full rounded-r-none border shadow-lg" />
</NotificationProvider> </NotificationProvider>
</CurrentRelaysProvider> </CurrentRelaysProvider>
</SecondaryPageContext.Provider> </SecondaryPageContext.Provider>
@ -407,20 +407,20 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
<Sidebar /> <Sidebar />
<div <div
className={cn( className={cn(
'grid grid-cols-2 w-full', 'grid w-full grid-cols-2',
themeSetting === 'pure-black' ? '' : 'gap-2 pr-2 py-2' themeSetting === 'pure-black' ? '' : 'gap-2 py-2 pr-2'
)} )}
> >
<div <div
className={cn( className={cn(
'bg-background overflow-hidden', 'overflow-hidden bg-background',
themeSetting === 'pure-black' ? 'border-l' : 'rounded-2xl shadow-lg' themeSetting === 'pure-black' ? 'border-l' : 'rounded-2xl shadow-lg'
)} )}
> >
{primaryPages.map(({ name, element, props }) => ( {primaryPages.map(({ name, element, props }) => (
<div <div
key={name} key={name}
className="flex flex-col h-full w-full" className="flex h-full w-full flex-col"
style={{ style={{
display: currentPrimaryPage === name ? 'block' : 'none' display: currentPrimaryPage === name ? 'block' : 'none'
}} }}
@ -431,7 +431,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
</div> </div>
<div <div
className={cn( className={cn(
'bg-background overflow-hidden', 'overflow-hidden bg-background',
themeSetting === 'pure-black' ? 'border-l' : 'rounded-2xl', themeSetting === 'pure-black' ? 'border-l' : 'rounded-2xl',
themeSetting !== 'pure-black' && secondaryStack.length > 0 && 'shadow-lg', themeSetting !== 'pure-black' && secondaryStack.length > 0 && 'shadow-lg',
secondaryStack.length === 0 ? 'bg-surface' : '' secondaryStack.length === 0 ? 'bg-surface' : ''
@ -440,7 +440,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
{secondaryStack.map((item, index) => ( {secondaryStack.map((item, index) => (
<div <div
key={item.index} key={item.index}
className="flex flex-col h-full w-full" className="flex h-full w-full flex-col"
style={{ display: index === secondaryStack.length - 1 ? 'block' : 'none' }} style={{ display: index === secondaryStack.length - 1 ? 'block' : 'none' }}
> >
{item.element} {item.element}
@ -451,7 +451,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
</div> </div>
</div> </div>
<TooManyRelaysAlertDialog /> <TooManyRelaysAlertDialog />
<BackgroundAudio className="fixed bottom-20 right-0 z-50 w-80 rounded-l-full rounded-r-none overflow-hidden shadow-lg border" /> <BackgroundAudio className="fixed bottom-20 right-0 z-50 w-80 overflow-hidden rounded-l-full rounded-r-none border shadow-lg" />
</NotificationProvider> </NotificationProvider>
</CurrentRelaysProvider> </CurrentRelaysProvider>
</SecondaryPageContext.Provider> </SecondaryPageContext.Provider>

View file

@ -40,7 +40,7 @@ export default function AboutInfoDialog({ children }: { children: React.ReactNod
<Drawer open={open} onOpenChange={setOpen}> <Drawer open={open} onOpenChange={setOpen}>
<DrawerTrigger asChild>{children}</DrawerTrigger> <DrawerTrigger asChild>{children}</DrawerTrigger>
<DrawerContent> <DrawerContent>
<div className="p-4 space-y-4">{content}</div> <div className="space-y-4 p-4">{content}</div>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
) )

View file

@ -37,18 +37,18 @@ export default function AccountList({
.finally(() => setSwitchingAccount(null)) .finally(() => setSwitchingAccount(null))
}} }}
> >
<div className="flex justify-between items-center p-2"> <div className="flex items-center justify-between p-2">
<div className="flex-1 flex items-center gap-2 relative"> <div className="relative flex flex-1 items-center gap-2">
<SimpleUserAvatar userId={act.pubkey} /> <SimpleUserAvatar userId={act.pubkey} />
<div className="flex-1 w-0"> <div className="w-0 flex-1">
<SimpleUsername userId={act.pubkey} className="font-semibold truncate" /> <SimpleUsername userId={act.pubkey} className="truncate font-semibold" />
<div className="text-sm rounded-full bg-muted px-2 w-fit"> <div className="w-fit rounded-full bg-muted px-2 text-sm">
{formatPubkey(act.pubkey)} {formatPubkey(act.pubkey)}
</div> </div>
</div> </div>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="flex gap-2 items-center"> <div className="flex items-center gap-2">
<SignerTypeBadge signerType={act.signerType} /> <SignerTypeBadge signerType={act.signerType} />
</div> </div>
<Button <Button
@ -65,7 +65,7 @@ export default function AccountList({
</div> </div>
</div> </div>
{switchingAccount && isSameAccount(act, switchingAccount) && ( {switchingAccount && isSameAccount(act, switchingAccount) && (
<div className="absolute top-0 left-0 flex w-full h-full items-center justify-center rounded-lg bg-muted/60"> <div className="absolute left-0 top-0 flex h-full w-full items-center justify-center rounded-lg bg-muted/60">
<Loader size={16} className="animate-spin" /> <Loader size={16} className="animate-spin" />
</div> </div>
)} )}

View file

@ -42,7 +42,7 @@ export default function BunkerLogin({
onChange={handleInputChange} onChange={handleInputChange}
className={errMsg ? 'border-destructive' : ''} className={errMsg ? 'border-destructive' : ''}
/> />
{errMsg && <div className="text-xs text-destructive pl-3">{errMsg}</div>} {errMsg && <div className="pl-3 text-xs text-destructive">{errMsg}</div>}
</div> </div>
<Button onClick={handleLogin} disabled={pending}> <Button onClick={handleLogin} disabled={pending}>
<Loader className={pending ? 'animate-spin' : 'hidden'} /> <Loader className={pending ? 'animate-spin' : 'hidden'} />

View file

@ -186,17 +186,17 @@ export default function NostrConnectLogin({
return ( return (
<div className="relative flex flex-col gap-4"> <div className="relative flex flex-col gap-4">
<div ref={qrContainerRef} className="flex flex-col items-center w-full space-y-3 mb-3"> <div ref={qrContainerRef} className="mb-3 flex w-full flex-col items-center space-y-3">
<a href={loginDetails.connectionString} aria-label="Open with Nostr signer app"> <a href={loginDetails.connectionString} aria-label="Open with Nostr signer app">
<QrCode size={qrCodeSize} value={loginDetails.connectionString} /> <QrCode size={qrCodeSize} value={loginDetails.connectionString} />
</a> </a>
{nostrConnectionErrMsg && ( {nostrConnectionErrMsg && (
<div className="text-xs text-destructive text-center pt-1">{nostrConnectionErrMsg}</div> <div className="pt-1 text-center text-xs text-destructive">{nostrConnectionErrMsg}</div>
)} )}
</div> </div>
<div className="flex justify-center w-full mb-3"> <div className="mb-3 flex w-full justify-center">
<div <div
className="flex items-center gap-2 text-sm text-muted-foreground bg-muted px-3 py-2 rounded-full cursor-pointer transition-all hover:bg-muted/80" className="flex cursor-pointer items-center gap-2 rounded-full bg-muted px-3 py-2 text-sm text-muted-foreground transition-all hover:bg-muted/80"
style={{ style={{
width: qrCodeSize > 0 ? `${Math.max(150, Math.min(qrCodeSize, 320))}px` : 'auto' width: qrCodeSize > 0 ? `${Math.max(150, Math.min(qrCodeSize, 320))}px` : 'auto'
}} }}
@ -204,14 +204,14 @@ export default function NostrConnectLogin({
role="button" role="button"
tabIndex={0} tabIndex={0}
> >
<div className="flex-grow min-w-0 truncate select-none"> <div className="min-w-0 flex-grow select-none truncate">
{loginDetails.connectionString} {loginDetails.connectionString}
</div> </div>
<div className="flex-shrink-0">{copied ? <Check size={14} /> : <Copy size={14} />}</div> <div className="flex-shrink-0">{copied ? <Check size={14} /> : <Copy size={14} />}</div>
</div> </div>
</div> </div>
<div className="flex items-center w-full my-4"> <div className="my-4 flex w-full items-center">
<div className="flex-grow border-t border-border/40"></div> <div className="flex-grow border-t border-border/40"></div>
<span className="px-3 text-xs text-muted-foreground">OR</span> <span className="px-3 text-xs text-muted-foreground">OR</span>
<div className="flex-grow border-t border-border/40"></div> <div className="flex-grow border-t border-border/40"></div>
@ -219,7 +219,7 @@ export default function NostrConnectLogin({
<div className="w-full space-y-1"> <div className="w-full space-y-1">
<div className="flex items-start space-x-2"> <div className="flex items-start space-x-2">
<div className="flex-1 relative"> <div className="relative flex-1">
<Input <Input
placeholder="bunker://..." placeholder="bunker://..."
value={bunkerInput} value={bunkerInput}
@ -229,7 +229,7 @@ export default function NostrConnectLogin({
<Button <Button
size="sm" size="sm"
variant="ghost" variant="ghost"
className="absolute right-1 top-1/2 -translate-y-1/2 h-8 w-8 p-0" className="absolute right-1 top-1/2 h-8 w-8 -translate-y-1/2 p-0"
onClick={startQrScan} onClick={startQrScan}
disabled={pending} disabled={pending}
> >
@ -237,21 +237,21 @@ export default function NostrConnectLogin({
</Button> </Button>
</div> </div>
<Button onClick={() => handleLogin()} disabled={pending}> <Button onClick={() => handleLogin()} disabled={pending}>
<Loader className={pending ? 'animate-spin mr-2' : 'hidden'} /> <Loader className={pending ? 'mr-2 animate-spin' : 'hidden'} />
{t('Login')} {t('Login')}
</Button> </Button>
</div> </div>
{errMsg && <div className="text-xs text-destructive pl-3 pt-1">{errMsg}</div>} {errMsg && <div className="pl-3 pt-1 text-xs text-destructive">{errMsg}</div>}
</div> </div>
<Button variant="secondary" onClick={back} className="w-full"> <Button variant="secondary" onClick={back} className="w-full">
{t('Back')} {t('Back')}
</Button> </Button>
<div className={cn('w-full h-full flex justify-center', isScanning ? '' : 'hidden')}> <div className={cn('flex h-full w-full justify-center', isScanning ? '' : 'hidden')}>
<video <video
ref={videoRef} ref={videoRef}
className="absolute inset-0 w-full h-full bg-background" className="absolute inset-0 h-full w-full bg-background"
autoPlay autoPlay
playsInline playsInline
muted muted
@ -259,7 +259,7 @@ export default function NostrConnectLogin({
<Button <Button
variant="secondary" variant="secondary"
size="sm" size="sm"
className="absolute top-2 right-2" className="absolute right-2 top-2"
onClick={stopQrScan} onClick={stopQrScan}
> >
Cancel Cancel

View file

@ -42,7 +42,7 @@ export default function NpubLogin({
onChange={handleInputChange} onChange={handleInputChange}
className={errMsg ? 'border-destructive' : ''} className={errMsg ? 'border-destructive' : ''}
/> />
{errMsg && <div className="text-xs text-destructive pl-3">{errMsg}</div>} {errMsg && <div className="pl-3 text-xs text-destructive">{errMsg}</div>}
</div> </div>
<Button onClick={handleLogin} disabled={pending}> <Button onClick={handleLogin} disabled={pending}>
<Loader className={pending ? 'animate-spin' : 'hidden'} /> <Loader className={pending ? 'animate-spin' : 'hidden'} />

View file

@ -53,7 +53,7 @@ export default function Signup({
{(['generate', 'password'] as Step[]).map((s, index) => ( {(['generate', 'password'] as Step[]).map((s, index) => (
<div key={s} className="flex items-center"> <div key={s} className="flex items-center">
<div <div
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold ${ className={`flex h-8 w-8 items-center justify-center rounded-full text-sm font-semibold ${
step === s step === s
? 'bg-primary text-primary-foreground' ? 'bg-primary text-primary-foreground'
: step === 'password' && s === 'generate' : step === 'password' && s === 'generate'
@ -63,7 +63,7 @@ export default function Signup({
> >
{index + 1} {index + 1}
</div> </div>
{index < 1 && <div className="w-12 h-0.5 bg-muted mx-1" />} {index < 1 && <div className="mx-1 h-0.5 w-12 bg-muted" />}
</div> </div>
))} ))}
</div> </div>
@ -75,7 +75,7 @@ export default function Signup({
{renderStepIndicator()} {renderStepIndicator()}
<div className="text-center"> <div className="text-center">
<h3 className="text-lg font-semibold mb-2">{t('Create Your Nostr Account')}</h3> <h3 className="mb-2 text-lg font-semibold">{t('Create Your Nostr Account')}</h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{t('Generate your unique private key. This is your digital identity.')} {t('Generate your unique private key. This is your digital identity.')}
</p> </p>
@ -110,7 +110,7 @@ export default function Signup({
</div> </div>
</div> </div>
<div className="w-full flex flex-wrap gap-2"> <div className="flex w-full flex-wrap gap-2">
<Button onClick={handleDownload} className="flex-1"> <Button onClick={handleDownload} className="flex-1">
<Download /> <Download />
{t('Download Backup File')} {t('Download Backup File')}
@ -129,7 +129,7 @@ export default function Signup({
</Button> </Button>
</div> </div>
<div className="flex items-center gap-2 ml-2"> <div className="ml-2 flex items-center gap-2">
<Checkbox <Checkbox
id="acknowledge-checkbox" id="acknowledge-checkbox"
checked={checkedSaveKey} checked={checkedSaveKey}
@ -159,7 +159,7 @@ export default function Signup({
{renderStepIndicator()} {renderStepIndicator()}
<div className="text-center"> <div className="text-center">
<h3 className="text-lg font-semibold mb-2">{t('Secure Your Account')}</h3> <h3 className="mb-2 text-lg font-semibold">{t('Secure Your Account')}</h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{t('Add an extra layer of protection with a password')} {t('Add an extra layer of protection with a password')}
</p> </p>
@ -201,7 +201,7 @@ export default function Signup({
)} )}
</div> </div>
<div className="w-full flex gap-2"> <div className="flex w-full gap-2">
<Button <Button
variant="secondary" variant="secondary"
onClick={() => { onClick={() => {

View file

@ -45,10 +45,10 @@ function AccountManagerNav({
return ( return (
<div onClick={(e) => e.stopPropagation()} className="flex flex-col gap-8"> <div onClick={(e) => e.stopPropagation()} className="flex flex-col gap-8">
<div> <div>
<div className="text-center text-muted-foreground text-sm font-semibold"> <div className="text-center text-sm font-semibold text-muted-foreground">
{t('Add an Account')} {t('Add an Account')}
</div> </div>
<div className="space-y-2 mt-4"> <div className="mt-4 space-y-2">
{!!window.nostr && ( {!!window.nostr && (
<Button onClick={() => nip07Login().then(() => close?.())} className="w-full"> <Button onClick={() => nip07Login().then(() => close?.())} className="w-full">
{t('Login with Browser Extension')} {t('Login with Browser Extension')}
@ -69,10 +69,10 @@ function AccountManagerNav({
</div> </div>
<Separator /> <Separator />
<div> <div>
<div className="text-center text-muted-foreground text-sm font-semibold"> <div className="text-center text-sm font-semibold text-muted-foreground">
{t("Don't have an account yet?")} {t("Don't have an account yet?")}
</div> </div>
<Button onClick={() => setPage('signup')} className="w-full mt-4"> <Button onClick={() => setPage('signup')} className="mt-4 w-full">
{t('Create New Account')} {t('Create New Account')}
</Button> </Button>
</div> </div>
@ -80,7 +80,7 @@ function AccountManagerNav({
<> <>
<Separator /> <Separator />
<div> <div>
<div className="text-center text-muted-foreground text-sm font-semibold"> <div className="text-center text-sm font-semibold text-muted-foreground">
{t('Logged in Accounts')} {t('Logged in Accounts')}
</div> </div>
<AccountList className="mt-4" afterSwitch={() => close?.()} /> <AccountList className="mt-4" afterSwitch={() => close?.()} />

View file

@ -129,7 +129,7 @@ export default function AudioPlayer({
<div <div
ref={containerRef} ref={containerRef}
className={cn( className={cn(
'flex items-center gap-3 py-2 px-2 border rounded-full max-w-md bg-background', 'flex max-w-md items-center gap-3 rounded-full border bg-background px-2 py-2',
className className
)} )}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
@ -137,12 +137,12 @@ export default function AudioPlayer({
<audio ref={audioRef} src={src} preload="metadata" onError={() => setError(false)} /> <audio ref={audioRef} src={src} preload="metadata" onError={() => setError(false)} />
{/* Play/Pause Button */} {/* Play/Pause Button */}
<Button size="icon" className="rounded-full shrink-0" onClick={togglePlay}> <Button size="icon" className="shrink-0 rounded-full" onClick={togglePlay}>
{isPlaying ? <Pause fill="currentColor" /> : <Play fill="currentColor" />} {isPlaying ? <Pause fill="currentColor" /> : <Play fill="currentColor" />}
</Button> </Button>
{/* Progress Section */} {/* Progress Section */}
<div className="flex-1 relative"> <div className="relative flex-1">
<Slider <Slider
value={[currentTime]} value={[currentTime]}
max={duration || 100} max={duration || 100}
@ -153,14 +153,14 @@ export default function AudioPlayer({
/> />
</div> </div>
<div className="text-sm font-mono text-muted-foreground"> <div className="font-mono text-sm text-muted-foreground">
{formatTime(Math.max(duration - currentTime, 0))} {formatTime(Math.max(duration - currentTime, 0))}
</div> </div>
{isMinimized ? ( {isMinimized ? (
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="rounded-full shrink-0 text-muted-foreground" className="shrink-0 rounded-full text-muted-foreground"
onClick={() => mediaManager.stopAudioBackground()} onClick={() => mediaManager.stopAudioBackground()}
> >
<X /> <X />
@ -169,7 +169,7 @@ export default function AudioPlayer({
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="rounded-full shrink-0 text-muted-foreground" className="shrink-0 rounded-full text-muted-foreground"
onClick={() => mediaManager.playAudioBackground(src, audioRef.current?.currentTime || 0)} onClick={() => mediaManager.playAudioBackground(src, audioRef.current?.currentTime || 0)}
> >
<Minimize2 /> <Minimize2 />

View file

@ -52,7 +52,7 @@ export default function BookmarkButton({ stuff }: { stuff: Event | string }) {
<button <button
className={`flex items-center gap-1 ${ className={`flex items-center gap-1 ${
isBookmarked ? 'text-rose-400' : 'text-muted-foreground' isBookmarked ? 'text-rose-400' : 'text-muted-foreground'
} enabled:hover:text-rose-400 px-3 h-full disabled:text-muted-foreground/40 disabled:cursor-default`} } h-full px-3 enabled:hover:text-rose-400 disabled:cursor-default disabled:text-muted-foreground/40`}
onClick={isBookmarked ? handleRemoveBookmark : handleBookmark} onClick={isBookmarked ? handleRemoveBookmark : handleBookmark}
disabled={!event || updating} disabled={!event || updating}
title={isBookmarked ? t('Remove bookmark') : t('Bookmark')} title={isBookmarked ? t('Remove bookmark') : t('Bookmark')}

View file

@ -62,7 +62,7 @@ export default function BookmarkList() {
if (eventIds.length === 0) { if (eventIds.length === 0) {
return ( return (
<div className="mt-2 text-sm text-center text-muted-foreground"> <div className="mt-2 text-center text-sm text-muted-foreground">
{t('no bookmarks found')} {t('no bookmarks found')}
</div> </div>
) )
@ -79,7 +79,7 @@ export default function BookmarkList() {
<NoteCardLoadingSkeleton /> <NoteCardLoadingSkeleton />
</div> </div>
) : ( ) : (
<div className="text-center text-sm text-muted-foreground mt-2"> <div className="mt-2 text-center text-sm text-muted-foreground">
{t('no more bookmarks')} {t('no more bookmarks')}
</div> </div>
)} )}

View file

@ -42,10 +42,10 @@ export default function AccountButton() {
profile ? ( profile ? (
<SimpleUserAvatar <SimpleUserAvatar
userId={pubkey} userId={pubkey}
className={cn('size-6', active ? 'ring-primary ring-2' : '')} className={cn('size-6', active ? 'ring-2 ring-primary' : '')}
/> />
) : ( ) : (
<Skeleton className={cn('size-6 rounded-full', active ? 'ring-primary ring-2' : '')} /> <Skeleton className={cn('size-6 rounded-full', active ? 'ring-2 ring-primary' : '')} />
) )
) : ( ) : (
<UserRound /> <UserRound />

View file

@ -18,7 +18,7 @@ export default function BottomNavigationBarItem({
return ( return (
<Button <Button
className={cn( className={cn(
'flex shadow-none items-center bg-transparent w-full h-12 p-3 m-0 rounded-lg [&_svg]:size-6', 'm-0 flex h-12 w-full items-center rounded-lg bg-transparent p-3 shadow-none [&_svg]:size-6',
active && 'text-primary hover:text-primary' active && 'text-primary hover:text-primary'
)} )}
variant="ghost" variant="ghost"

View file

@ -17,7 +17,7 @@ export default function NotificationsButton() {
<div className="relative"> <div className="relative">
<Bell /> <Bell />
{hasNewNotification && ( {hasNewNotification && (
<div className="absolute -top-0.5 right-0.5 w-2 h-2 ring-2 ring-background bg-primary rounded-full" /> <div className="absolute -top-0.5 right-0.5 h-2 w-2 rounded-full bg-primary ring-2 ring-background" />
)} )}
</div> </div>
</BottomNavigationBarItem> </BottomNavigationBarItem>

View file

@ -8,13 +8,13 @@ import NotificationsButton from './NotificationsButton'
export default function BottomNavigationBar() { export default function BottomNavigationBar() {
return ( return (
<div <div
className={cn('fixed bottom-0 w-full z-40 bg-background border-t')} className={cn('fixed bottom-0 z-40 w-full border-t bg-background')}
style={{ style={{
paddingBottom: 'env(safe-area-inset-bottom)' paddingBottom: 'env(safe-area-inset-bottom)'
}} }}
> >
<BackgroundAudio className="rounded-none border-x-0 border-t-0 border-b bg-background" /> <BackgroundAudio className="rounded-none border-x-0 border-b border-t-0 bg-background" />
<div className="w-full flex justify-around items-center [&_svg]:size-4 [&_svg]:shrink-0"> <div className="flex w-full items-center justify-around [&_svg]:size-4 [&_svg]:shrink-0">
<HomeButton /> <HomeButton />
<ExploreButton /> <ExploreButton />
<NotificationsButton /> <NotificationsButton />

View file

@ -10,7 +10,7 @@ export default function ClientTag({ event }: { event: NostrEvent }) {
if (!usingClient) return null if (!usingClient) return null
return ( return (
<span className="text-sm text-muted-foreground shrink-0"> <span className="shrink-0 text-sm text-muted-foreground">
{t('via {{client}}', { client: usingClient })} {t('via {{client}}', { client: usingClient })}
</span> </span>
) )

View file

@ -48,7 +48,7 @@ export default function Collapsible({
return ( return (
<div <div
className={cn('relative text-left overflow-hidden', className)} className={cn('relative overflow-hidden text-left', className)}
ref={containerRef} ref={containerRef}
{...props} {...props}
style={{ style={{
@ -57,8 +57,8 @@ export default function Collapsible({
> >
{children} {children}
{shouldCollapse && !expanded && ( {shouldCollapse && !expanded && (
<div className="absolute bottom-0 h-40 w-full z-10 bg-gradient-to-b from-transparent to-background/90 flex items-end justify-center pb-4"> <div className="absolute bottom-0 z-10 flex h-40 w-full items-end justify-center bg-gradient-to-b from-transparent to-background/90 pb-4">
<div className="bg-background rounded-lg"> <div className="rounded-lg bg-background">
<Button <Button
className="bg-foreground hover:bg-foreground/80" className="bg-foreground hover:bg-foreground/80"
onClick={(e) => { onClick={(e) => {

View file

@ -110,7 +110,7 @@ export default function Content({
let imageIndex = 0 let imageIndex = 0
return ( return (
<> <>
<div ref={contentRef} className={cn('text-wrap break-words whitespace-pre-wrap', className)}> <div ref={contentRef} className={cn('whitespace-pre-wrap text-wrap break-words', className)}>
{nodes.map((node, index) => { {nodes.map((node, index) => {
if (node.type === 'text') { if (node.type === 'text') {
return node.data return node.data

View file

@ -16,7 +16,7 @@ export default function CommunityDefinitionPreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Community')}] <span className="italic pr-0.5">{metadata.name}</span> [{t('Community')}] <span className="pr-0.5 italic">{metadata.name}</span>
</div> </div>
) )
} }

View file

@ -16,7 +16,7 @@ export default function EmojiPackPreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Emoji Pack')}] <span className="italic pr-0.5">{title}</span> [{t('Emoji Pack')}] <span className="pr-0.5 italic">{title}</span>
{emojis.length > 0 && <span>({emojis.length})</span>} {emojis.length > 0 && <span>({emojis.length})</span>}
</div> </div>
) )

View file

@ -16,7 +16,7 @@ export default function FollowPackPreview({
return ( return (
<div className={cn('truncate', className)}> <div className={cn('truncate', className)}>
[{t('Follow Pack')}] <span className="italic pr-0.5">{title}</span> [{t('Follow Pack')}] <span className="pr-0.5 italic">{title}</span>
</div> </div>
) )
} }

View file

@ -16,7 +16,7 @@ export default function GroupMetadataPreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Group')}] <span className="italic pr-0.5">{metadata.name}</span> [{t('Group')}] <span className="pr-0.5 italic">{metadata.name}</span>
</div> </div>
) )
} }

View file

@ -23,7 +23,7 @@ export default function HighlightPreview({
<Content <Content
content={translatedEvent?.content ?? event.content} content={translatedEvent?.content ?? event.content}
emojiInfos={emojiInfos} emojiInfos={emojiInfos}
className="italic pr-0.5" className="pr-0.5 italic"
/> />
</div> </div>
) )

View file

@ -16,7 +16,7 @@ export default function LiveEventPreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Live event')}] <span className="italic pr-0.5">{metadata.title}</span> [{t('Live event')}] <span className="pr-0.5 italic">{metadata.title}</span>
</div> </div>
) )
} }

View file

@ -16,7 +16,7 @@ export default function LongFormArticlePreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Article')}] <span className="italic pr-0.5">{metadata.title}</span> [{t('Article')}] <span className="pr-0.5 italic">{metadata.title}</span>
</div> </div>
) )
} }

View file

@ -13,7 +13,7 @@ export default function PictureNotePreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Image')}] <span className="italic pr-0.5">{event.content}</span> [{t('Image')}] <span className="pr-0.5 italic">{event.content}</span>
</div> </div>
) )
} }

View file

@ -17,7 +17,7 @@ export default function PollPreview({ event, className }: { event: Event; classN
<Content <Content
content={translatedEvent?.content ?? event.content} content={translatedEvent?.content ?? event.content}
emojiInfos={emojiInfos} emojiInfos={emojiInfos}
className="italic pr-0.5" className="pr-0.5 italic"
/> />
</div> </div>
) )

View file

@ -13,7 +13,7 @@ export default function VideoNotePreview({
return ( return (
<div className={cn('pointer-events-none', className)}> <div className={cn('pointer-events-none', className)}>
[{t('Media')}] <span className="italic pr-0.5">{event.content}</span> [{t('Media')}] <span className="pr-0.5 italic">{event.content}</span>
</div> </div>
) )
} }

View file

@ -85,23 +85,23 @@ export default function DefaultRelaysSetting() {
/> />
<Button onClick={saveNewRelayUrl}>{t('Add')}</Button> <Button onClick={saveNewRelayUrl}>{t('Add')}</Button>
</div> </div>
{newRelayUrlError && <div className="text-xs text-destructive mt-1">{newRelayUrlError}</div>} {newRelayUrlError && <div className="mt-1 text-xs text-destructive">{newRelayUrlError}</div>}
</div> </div>
) )
} }
function RelayUrl({ url, onRemove }: { url: string; onRemove: () => void }) { function RelayUrl({ url, onRemove }: { url: string; onRemove: () => void }) {
return ( return (
<div className="flex items-center justify-between pl-1 pr-3 py-1"> <div className="flex items-center justify-between py-1 pl-1 pr-3">
<div className="flex gap-3 items-center flex-1 w-0"> <div className="flex w-0 flex-1 items-center gap-3">
<RelayIcon url={url} className="w-4 h-4" /> <RelayIcon url={url} className="h-4 w-4" />
<div className="text-muted-foreground text-sm truncate">{url}</div> <div className="truncate text-sm text-muted-foreground">{url}</div>
</div> </div>
<div className="shrink-0"> <div className="shrink-0">
<CircleX <CircleX
size={16} size={16}
onClick={onRemove} onClick={onRemove}
className="text-muted-foreground hover:text-destructive cursor-pointer" className="cursor-pointer text-muted-foreground hover:text-destructive"
/> />
</div> </div>
</div> </div>

View file

@ -7,10 +7,10 @@ export default function PlatinumSponsors() {
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<div className="font-semibold text-center">{t('Platinum Sponsors')}</div> <div className="text-center font-semibold">{t('Platinum Sponsors')}</div>
<div className="flex flex-col gap-2 items-center"> <div className="flex flex-col items-center gap-2">
<div <div
className="flex items-center gap-4 cursor-pointer" className="flex cursor-pointer items-center gap-4"
onClick={() => window.open('https://opensats.org/', '_blank')} onClick={() => window.open('https://opensats.org/', '_blank')}
> >
<Image <Image

View file

@ -21,23 +21,23 @@ export default function RecentSupporters() {
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<div className="font-semibold text-center">{t('Recent Supporters')}</div> <div className="text-center font-semibold">{t('Recent Supporters')}</div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{supporters.map((item, index) => ( {supporters.map((item, index) => (
<div <div
key={index} key={index}
className="flex items-center justify-between rounded-md border p-2 sm:p-4 gap-2" className="flex items-center justify-between gap-2 rounded-md border p-2 sm:p-4"
> >
<div className="flex items-center gap-2 flex-1 w-0"> <div className="flex w-0 flex-1 items-center gap-2">
<UserAvatar userId={item.pubkey} /> <UserAvatar userId={item.pubkey} />
<div className="flex-1 w-0"> <div className="w-0 flex-1">
<Username className="font-semibold w-fit" userId={item.pubkey} /> <Username className="w-fit font-semibold" userId={item.pubkey} />
<div className="text-xs text-muted-foreground line-clamp-3 select-text"> <div className="line-clamp-3 select-text text-xs text-muted-foreground">
{item.comment} {item.comment}
</div> </div>
</div> </div>
</div> </div>
<div className="font-semibold text-yellow-400 shrink-0"> <div className="shrink-0 font-semibold text-yellow-400">
{formatAmount(item.amount)} {t('sats')} {formatAmount(item.amount)} {t('sats')}
</div> </div>
</div> </div>

View file

@ -13,12 +13,12 @@ export default function Donation({ className }: { className?: string }) {
const [donationAmount, setDonationAmount] = useState<number | undefined>(undefined) const [donationAmount, setDonationAmount] = useState<number | undefined>(undefined)
return ( return (
<div className={cn('p-4 border rounded-lg space-y-4', className)}> <div className={cn('space-y-4 rounded-lg border p-4', className)}>
<div className="text-center font-semibold">{t('Enjoying Jumble?')}</div> <div className="text-center font-semibold">{t('Enjoying Jumble?')}</div>
<div className="text-center text-muted-foreground"> <div className="text-center text-muted-foreground">
{t('Your donation helps me maintain Jumble and make it better! 😊')} {t('Your donation helps me maintain Jumble and make it better! 😊')}
</div> </div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4"> <div className="grid grid-cols-2 gap-4 lg:grid-cols-4">
{[ {[
{ amount: 1000, text: '☕️ 1k' }, { amount: 1000, text: '☕️ 1k' },
{ amount: 10000, text: '🍜 10k' }, { amount: 10000, text: '🍜 10k' },

View file

@ -15,7 +15,7 @@ export default function DrawerMenuItem({
<DrawerClose className="w-full"> <DrawerClose className="w-full">
<Button <Button
onClick={onClick} onClick={onClick}
className={cn('w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5', className)} className={cn('w-full justify-start gap-4 p-6 text-lg [&_svg]:size-5', className)}
variant="ghost" variant="ghost"
> >
{children} {children}

View file

@ -42,21 +42,21 @@ export function EmbeddedLNInvoice({ invoice, className }: { invoice: string; cla
return ( return (
<div <div
className={cn('p-3 border rounded-lg cursor-default flex flex-col gap-3 max-w-sm', className)} className={cn('flex max-w-sm cursor-default flex-col gap-3 rounded-lg border p-3', className)}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Zap className="w-5 h-5 text-yellow-400" /> <Zap className="h-5 w-5 text-yellow-400" />
<div className="font-semibold text-sm">{t('Lightning Invoice')}</div> <div className="text-sm font-semibold">{t('Lightning Invoice')}</div>
</div> </div>
{description && ( {description && (
<div className="text-sm text-muted-foreground break-words">{description}</div> <div className="break-words text-sm text-muted-foreground">{description}</div>
)} )}
<div className="text-lg font-bold"> <div className="text-lg font-bold">
{formatAmount(amount)} {t('sats')} {formatAmount(amount)} {t('sats')}
</div> </div>
<Button onClick={handlePayClick}> <Button onClick={handlePayClick}>
{paying && <Loader className="w-4 h-4 animate-spin" />} {paying && <Loader className="h-4 w-4 animate-spin" />}
{t('Pay')} {t('Pay')}
</Button> </Button>
</div> </div>

View file

@ -6,7 +6,7 @@ export function EmbeddedMention({ userId, className }: { userId: string; classNa
<Username <Username
userId={userId} userId={userId}
showAt showAt
className={cn('text-primary font-normal inline', className)} className={cn('inline font-normal text-primary', className)}
withoutSkeleton withoutSkeleton
/> />
) )

View file

@ -29,18 +29,18 @@ export function EmbeddedNote({ noteId, className }: { noteId: string; className?
function EmbeddedNoteSkeleton({ className }: { className?: string }) { function EmbeddedNoteSkeleton({ className }: { className?: string }) {
return ( return (
<div <div
className={cn('text-left p-2 sm:p-3 border rounded-xl bg-card', className)} className={cn('rounded-xl border bg-card p-2 text-left sm:p-3', className)}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Skeleton className="w-9 h-9 rounded-full" /> <Skeleton className="h-9 w-9 rounded-full" />
<div> <div>
<Skeleton className="h-3 w-16 my-1" /> <Skeleton className="my-1 h-3 w-16" />
<Skeleton className="h-3 w-16 my-1" /> <Skeleton className="my-1 h-3 w-16" />
</div> </div>
</div> </div>
<Skeleton className="w-full h-4 my-1 mt-2" /> <Skeleton className="my-1 mt-2 h-4 w-full" />
<Skeleton className="w-2/3 h-4 my-1" /> <Skeleton className="my-1 h-4 w-2/3" />
</div> </div>
) )
} }
@ -49,10 +49,10 @@ function EmbeddedNoteNotFound({ noteId, className }: { noteId: string; className
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<div className={cn('text-left p-2 sm:p-3 border rounded-xl bg-card', className)}> <div className={cn('rounded-xl border bg-card p-2 text-left sm:p-3', className)}>
<div className="flex flex-col items-center text-muted-foreground font-medium gap-2"> <div className="flex flex-col items-center gap-2 font-medium text-muted-foreground">
<div>{t('Sorry! The note cannot be found 😔')}</div> <div>{t('Sorry! The note cannot be found 😔')}</div>
<ClientSelect className="w-full mt-2" originalNoteId={noteId} /> <ClientSelect className="mt-2 w-full" originalNoteId={noteId} />
</div> </div>
</div> </div>
) )

View file

@ -12,7 +12,7 @@ export function EmbeddedWebsocketUrl({ url }: { url: string }) {
}} }}
> >
[ {url} ] [ {url} ]
<span className="w-2 h-1 bg-primary" /> <span className="h-1 w-2 bg-primary" />
</span> </span>
) )
} }

View file

@ -17,7 +17,7 @@ export default function Emoji({
if (typeof emoji === 'string') { if (typeof emoji === 'string') {
return emoji === '+' ? ( return emoji === '+' ? (
<Heart className={cn('size-5 text-red-400 fill-red-400', classNames?.img)} /> <Heart className={cn('size-5 fill-red-400 text-red-400', classNames?.img)} />
) : ( ) : (
<span className={cn('whitespace-nowrap', classNames?.text)}>{emoji}</span> <span className={cn('whitespace-nowrap', classNames?.text)}>{emoji}</span>
) )
@ -34,7 +34,7 @@ export default function Emoji({
src={emoji.url} src={emoji.url}
alt={emoji.shortcode} alt={emoji.shortcode}
draggable={false} draggable={false}
className={cn('inline-block size-5 pointer-events-none', classNames?.img)} className={cn('pointer-events-none inline-block size-5', classNames?.img)}
onLoad={() => { onLoad={() => {
setHasError(false) setHasError(false)
}} }}

View file

@ -56,7 +56,7 @@ export default function EmojiPackList() {
if (eventIds.length === 0) { if (eventIds.length === 0) {
return ( return (
<div className="mt-2 text-sm text-center text-muted-foreground"> <div className="mt-2 text-center text-sm text-muted-foreground">
{t('no emoji packs found')} {t('no emoji packs found')}
</div> </div>
) )

View file

@ -39,7 +39,7 @@ export default function EmojiPickerDialog({
return ( return (
<DropdownMenu open={open} onOpenChange={setOpen}> <DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger> <DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
<DropdownMenuContent side="top" className="p-0 w-fit"> <DropdownMenuContent side="top" className="w-fit p-0">
<EmojiPicker <EmojiPicker
onEmojiClick={(emoji, e) => { onEmojiClick={(emoji, e) => {
e.stopPropagation() e.stopPropagation()

View file

@ -28,9 +28,9 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
render() { render() {
if (this.state.hasError) { if (this.state.hasError) {
return ( return (
<div className="w-screen h-screen flex flex-col items-center justify-center p-4 gap-4"> <div className="flex h-screen w-screen flex-col items-center justify-center gap-4 p-4">
<h1 className="text-2xl font-bold">Oops, something went wrong.</h1> <h1 className="text-2xl font-bold">Oops, something went wrong.</h1>
<p className="text-lg text-center max-w-md"> <p className="max-w-md text-center text-lg">
Sorry for the inconvenience. If you don't mind helping, you can{' '} Sorry for the inconvenience. If you don't mind helping, you can{' '}
<a <a
href="https://github.com/CodyTseng/jumble/issues/new" href="https://github.com/CodyTseng/jumble/issues/new"
@ -61,7 +61,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
> >
Copy Error Message Copy Error Message
</Button> </Button>
<pre className="bg-destructive/10 text-destructive p-2 rounded text-wrap break-words whitespace-pre-wrap"> <pre className="whitespace-pre-wrap text-wrap break-words rounded bg-destructive/10 p-2 text-destructive">
Error: {this.state.error.message} Error: {this.state.error.message}
</pre> </pre>
</> </>

View file

@ -30,7 +30,7 @@ export default function Explore() {
<div className="p-4 max-md:border-b"> <div className="p-4 max-md:border-b">
<Skeleton className="h-6 w-20" /> <Skeleton className="h-6 w-20" />
</div> </div>
<div className="grid md:px-4 md:grid-cols-2 md:gap-2"> <div className="grid md:grid-cols-2 md:gap-2 md:px-4">
<RelaySimpleInfoSkeleton className="h-auto px-4 py-3 md:rounded-lg md:border" /> <RelaySimpleInfoSkeleton className="h-auto px-4 py-3 md:rounded-lg md:border" />
</div> </div>
</div> </div>
@ -62,13 +62,13 @@ function RelayCollection({ collection }: { collection: TAwesomeRelayCollection }
<div> <div>
<div <div
className={cn( className={cn(
'sticky bg-background z-20 px-4 py-3 text-2xl font-semibold max-md:border-b', 'sticky z-20 bg-background px-4 py-3 text-2xl font-semibold max-md:border-b',
deepBrowsing ? 'top-12' : 'top-24' deepBrowsing ? 'top-12' : 'top-24'
)} )}
> >
{collection.name} {collection.name}
</div> </div>
<div className="grid md:px-4 md:grid-cols-2 md:gap-3"> <div className="grid md:grid-cols-2 md:gap-3 md:px-4">
{collection.relays.map((url) => ( {collection.relays.map((url) => (
<RelayItem key={url} url={url} /> <RelayItem key={url} url={url} />
))} ))}
@ -82,7 +82,7 @@ function RelayItem({ url }: { url: string }) {
const { relayInfo, isFetching } = useFetchRelayInfo(url) const { relayInfo, isFetching } = useFetchRelayInfo(url)
if (isFetching) { if (isFetching) {
return <RelaySimpleInfoSkeleton className="h-auto px-4 py-3 border-b md:rounded-lg md:border" /> return <RelaySimpleInfoSkeleton className="h-auto border-b px-4 py-3 md:rounded-lg md:border" />
} }
if (!relayInfo) { if (!relayInfo) {
@ -92,7 +92,7 @@ function RelayItem({ url }: { url: string }) {
return ( return (
<RelaySimpleInfo <RelaySimpleInfo
key={relayInfo.url} key={relayInfo.url}
className="clickable h-auto px-4 py-3 border-b md:rounded-lg md:border" className="clickable h-auto border-b px-4 py-3 md:rounded-lg md:border"
relayInfo={relayInfo} relayInfo={relayInfo}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()

View file

@ -40,7 +40,7 @@ export default function ExternalContent({
if (node.type === 'text') { if (node.type === 'text') {
return ( return (
<div className={cn('text-wrap break-words whitespace-pre-wrap', className)}>{content}</div> <div className={cn('whitespace-pre-wrap text-wrap break-words', className)}>{content}</div>
) )
} }

View file

@ -37,13 +37,13 @@ export function Tabs({
return ( return (
<div className="w-fit"> <div className="w-fit">
<div className="flex relative"> <div className="relative flex">
{TABS.map((tab, index) => ( {TABS.map((tab, index) => (
<div <div
key={tab.value} key={tab.value}
ref={(el) => (tabRefs.current[index] = el)} ref={(el) => (tabRefs.current[index] = el)}
className={cn( className={cn(
`text-center px-4 py-2 font-semibold clickable cursor-pointer rounded-lg`, `clickable cursor-pointer rounded-lg px-4 py-2 text-center font-semibold`,
selectedTab === tab.value ? '' : 'text-muted-foreground' selectedTab === tab.value ? '' : 'text-muted-foreground'
)} )}
onClick={() => onTabChange(tab.value)} onClick={() => onTabChange(tab.value)}
@ -52,7 +52,7 @@ export function Tabs({
</div> </div>
))} ))}
<div <div
className="absolute bottom-0 h-1 bg-primary rounded-full transition-all duration-500" className="absolute bottom-0 h-1 rounded-full bg-primary transition-all duration-500"
style={{ style={{
width: `${indicatorStyle.width}px`, width: `${indicatorStyle.width}px`,
left: `${indicatorStyle.left}px` left: `${indicatorStyle.left}px`

View file

@ -32,12 +32,12 @@ export default function ExternalContentInteractions({
return ( return (
<> <>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<ScrollArea className="flex-1 w-0"> <ScrollArea className="w-0 flex-1">
<Tabs selectedTab={type} onTabChange={setType} /> <Tabs selectedTab={type} onTabChange={setType} />
<ScrollBar orientation="horizontal" className="opacity-0 pointer-events-none" /> <ScrollBar orientation="horizontal" className="pointer-events-none opacity-0" />
</ScrollArea> </ScrollArea>
<Separator orientation="vertical" className="h-6" /> <Separator orientation="vertical" className="h-6" />
<div className="size-10 flex items-center justify-center"> <div className="flex size-10 items-center justify-center">
<TrustScoreFilter filterId={SPECIAL_TRUST_SCORE_FILTER_ID.INTERACTIONS} /> <TrustScoreFilter filterId={SPECIAL_TRUST_SCORE_FILTER_ID.INTERACTIONS} />
</div> </div>
</div> </div>

View file

@ -92,7 +92,7 @@ export default function ExternalLink({
<div className="py-2"> <div className="py-2">
<Button <Button
onClick={handleOpenLink} onClick={handleOpenLink}
className="w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5" className="w-full justify-start gap-4 p-6 text-lg [&_svg]:size-5"
variant="ghost" variant="ghost"
> >
<ExternalLinkIcon /> <ExternalLinkIcon />
@ -100,7 +100,7 @@ export default function ExternalLink({
</Button> </Button>
<Button <Button
onClick={handleViewDiscussions} onClick={handleViewDiscussions}
className="w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5" className="w-full justify-start gap-4 p-6 text-lg [&_svg]:size-5"
variant="ghost" variant="ghost"
> >
<MessageSquare /> <MessageSquare />

View file

@ -40,7 +40,7 @@ export default function AddNewRelay() {
return ( return (
<div className="space-y-1"> <div className="space-y-1">
<div className="flex gap-2 items-center"> <div className="flex items-center gap-2">
<Input <Input
placeholder={t('Add a new relay')} placeholder={t('Add a new relay')}
value={input} value={input}
@ -50,7 +50,7 @@ export default function AddNewRelay() {
/> />
<Button onClick={saveRelay}>{t('Add')}</Button> <Button onClick={saveRelay}>{t('Add')}</Button>
</div> </div>
{errorMsg && <div className="text-destructive text-sm pl-8">{errorMsg}</div>} {errorMsg && <div className="pl-8 text-sm text-destructive">{errorMsg}</div>}
</div> </div>
) )
} }

View file

@ -28,7 +28,7 @@ export default function AddNewRelaySet() {
return ( return (
<div className="space-y-1"> <div className="space-y-1">
<div className="flex gap-2 items-center"> <div className="flex items-center gap-2">
<Input <Input
placeholder={t('Add a new relay set')} placeholder={t('Add a new relay set')}
value={newRelaySetName} value={newRelaySetName}

View file

@ -43,7 +43,7 @@ export default function FavoriteRelayList() {
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<div className="text-muted-foreground font-semibold select-none">{t('Relays')}</div> <div className="select-none font-semibold text-muted-foreground">{t('Relays')}</div>
<DndContext <DndContext
sensors={sensors} sensors={sensors}
collisionDetection={closestCenter} collisionDetection={closestCenter}

View file

@ -40,7 +40,7 @@ export default function PullRelaySetsButton() {
const trigger = ( const trigger = (
<Button <Button
variant="link" variant="link"
className="text-muted-foreground hover:no-underline hover:text-foreground p-0 h-fit" className="h-fit p-0 text-muted-foreground hover:text-foreground hover:no-underline"
disabled={!pubkey} disabled={!pubkey}
> >
<CloudDownload /> <CloudDownload />
@ -53,7 +53,7 @@ export default function PullRelaySetsButton() {
<Drawer open={open} onOpenChange={setOpen}> <Drawer open={open} onOpenChange={setOpen}>
<DrawerTrigger asChild>{trigger}</DrawerTrigger> <DrawerTrigger asChild>{trigger}</DrawerTrigger>
<DrawerContent className="max-h-[90vh]"> <DrawerContent className="max-h-[90vh]">
<div className="flex flex-col p-4 gap-4 overflow-auto"> <div className="flex flex-col gap-4 overflow-auto p-4">
<DrawerHeader> <DrawerHeader>
<DrawerTitle>{t('Select the relay sets you want to pull')}</DrawerTitle> <DrawerTitle>{t('Select the relay sets you want to pull')}</DrawerTitle>
<DrawerDescription className="hidden" /> <DrawerDescription className="hidden" />

View file

@ -20,22 +20,22 @@ export default function RelayItem({ relay }: { relay: string }) {
return ( return (
<div <div
className="relative group clickable flex gap-2 border rounded-lg p-2 pr-2.5 items-center justify-between select-none" className="clickable group relative flex select-none items-center justify-between gap-2 rounded-lg border p-2 pr-2.5"
ref={setNodeRef} ref={setNodeRef}
style={style} style={style}
onClick={() => push(toRelay(relay))} onClick={() => push(toRelay(relay))}
> >
<div className="flex items-center gap-1 flex-1"> <div className="flex flex-1 items-center gap-1">
<div <div
className="cursor-grab active:cursor-grabbing p-2 hover:bg-muted rounded touch-none shrink-0" className="shrink-0 cursor-grab touch-none rounded p-2 hover:bg-muted active:cursor-grabbing"
{...attributes} {...attributes}
{...listeners} {...listeners}
> >
<GripVertical className="size-4 text-muted-foreground" /> <GripVertical className="size-4 text-muted-foreground" />
</div> </div>
<div className="flex gap-2 items-center flex-1"> <div className="flex flex-1 items-center gap-2">
<RelayIcon url={relay} /> <RelayIcon url={relay} />
<div className="flex-1 w-0 truncate font-semibold">{relay}</div> <div className="w-0 flex-1 truncate font-semibold">{relay}</div>
</div> </div>
</div> </div>
<SaveRelayDropdownMenu urls={[relay]} /> <SaveRelayDropdownMenu urls={[relay]} />

View file

@ -42,19 +42,19 @@ export default function RelaySet({ relaySet }: { relaySet: TRelaySet }) {
} }
return ( return (
<div ref={setNodeRef} style={style} className="relative group"> <div ref={setNodeRef} style={style} className="group relative">
<div className="w-full border rounded-lg px-2 py-2.5"> <div className="w-full rounded-lg border px-2 py-2.5">
<div className="flex justify-between items-center"> <div className="flex items-center justify-between">
<div className="flex items-center"> <div className="flex items-center">
<div <div
className="cursor-grab active:cursor-grabbing p-2 hover:bg-muted rounded touch-none" className="cursor-grab touch-none rounded p-2 hover:bg-muted active:cursor-grabbing"
{...attributes} {...attributes}
{...listeners} {...listeners}
> >
<GripVertical className="size-4 text-muted-foreground" /> <GripVertical className="size-4 text-muted-foreground" />
</div> </div>
<div className="flex gap-2 items-center"> <div className="flex items-center gap-2">
<div className="flex justify-center items-center w-6 h-6 shrink-0"> <div className="flex h-6 w-6 shrink-0 items-center justify-center">
<FolderClosed className="size-4" /> <FolderClosed className="size-4" />
</div> </div>
<RelaySetName relaySet={relaySet} /> <RelaySetName relaySet={relaySet} />
@ -98,20 +98,20 @@ function RelaySetName({ relaySet }: { relaySet: TRelaySet }) {
} }
return renamingRelaySetId === relaySet.id ? ( return renamingRelaySetId === relaySet.id ? (
<div className="flex gap-1 items-center"> <div className="flex items-center gap-1">
<Input <Input
value={newSetName} value={newSetName}
onChange={handleRenameInputChange} onChange={handleRenameInputChange}
onBlur={saveNewRelaySetName} onBlur={saveNewRelaySetName}
onKeyDown={handleRenameInputKeyDown} onKeyDown={handleRenameInputKeyDown}
className="font-semibold w-28" className="w-28 font-semibold"
/> />
<Button variant="ghost" size="icon" onClick={saveNewRelaySetName}> <Button variant="ghost" size="icon" onClick={saveNewRelaySetName}>
<Check size={18} className="text-green-500" /> <Check size={18} className="text-green-500" />
</Button> </Button>
</div> </div>
) : ( ) : (
<div className="h-8 font-semibold flex items-center select-none">{relaySet.name}</div> <div className="flex h-8 select-none items-center font-semibold">{relaySet.name}</div>
) )
} }
@ -125,7 +125,7 @@ function RelayUrlsExpandToggle({
const { expandedRelaySetId, setExpandedRelaySetId } = useRelaySetsSettingComponent() const { expandedRelaySetId, setExpandedRelaySetId } = useRelaySetsSettingComponent()
return ( return (
<div <div
className="text-sm text-muted-foreground flex items-center gap-1 cursor-pointer hover:text-foreground" className="flex cursor-pointer items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
onClick={() => setExpandedRelaySetId((pre) => (pre === relaySetId ? null : relaySetId))} onClick={() => setExpandedRelaySetId((pre) => (pre === relaySetId ? null : relaySetId))}
> >
<div className="select-none">{children}</div> <div className="select-none">{children}</div>

View file

@ -45,7 +45,7 @@ export default function RelaySetList() {
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<div className="flex flex-wrap items-center justify-between gap-2"> <div className="flex flex-wrap items-center justify-between gap-2">
<div className="text-muted-foreground font-semibold select-none shrink-0"> <div className="shrink-0 select-none font-semibold text-muted-foreground">
{t('Relay sets')} {t('Relay sets')}
</div> </div>
<PullRelaySetsButton /> <PullRelaySetsButton />

View file

@ -73,7 +73,7 @@ export default function RelayUrls({ relaySetId }: { relaySetId: string }) {
/> />
<Button onClick={saveNewRelayUrl}>{t('Add')}</Button> <Button onClick={saveNewRelayUrl}>{t('Add')}</Button>
</div> </div>
{newRelayUrlError && <div className="text-xs text-destructive mt-1">{newRelayUrlError}</div>} {newRelayUrlError && <div className="mt-1 text-xs text-destructive">{newRelayUrlError}</div>}
</> </>
) )
} }
@ -81,15 +81,15 @@ export default function RelayUrls({ relaySetId }: { relaySetId: string }) {
function RelayUrl({ url, onRemove }: { url: string; onRemove: () => void }) { function RelayUrl({ url, onRemove }: { url: string; onRemove: () => void }) {
return ( return (
<div className="flex items-center justify-between pl-1 pr-3"> <div className="flex items-center justify-between pl-1 pr-3">
<div className="flex gap-3 items-center flex-1 w-0"> <div className="flex w-0 flex-1 items-center gap-3">
<RelayIcon url={url} className="w-4 h-4" /> <RelayIcon url={url} className="h-4 w-4" />
<div className="text-muted-foreground text-sm truncate">{url}</div> <div className="truncate text-sm text-muted-foreground">{url}</div>
</div> </div>
<div className="shrink-0"> <div className="shrink-0">
<CircleX <CircleX
size={16} size={16}
onClick={onRemove} onClick={onRemove}
className="text-muted-foreground hover:text-destructive cursor-pointer" className="cursor-pointer text-muted-foreground hover:text-destructive"
/> />
</div> </div>
</div> </div>

View file

@ -39,8 +39,8 @@ export default function FeedSwitcher({ close }: { close?: () => void }) {
close?.() close?.()
}} }}
> >
<div className="flex gap-3 items-center"> <div className="flex items-center gap-3">
<div className="flex justify-center items-center size-6 shrink-0"> <div className="flex size-6 shrink-0 items-center justify-center">
<UsersRound className="size-5" /> <UsersRound className="size-5" />
</div> </div>
<div className="flex-1">{t('Following')}</div> <div className="flex-1">{t('Following')}</div>
@ -56,8 +56,8 @@ export default function FeedSwitcher({ close }: { close?: () => void }) {
close?.() close?.()
}} }}
> >
<div className="flex gap-3 items-center"> <div className="flex items-center gap-3">
<div className="flex justify-center items-center size-6 shrink-0"> <div className="flex size-6 shrink-0 items-center justify-center">
<Star className="size-5" /> <Star className="size-5" />
</div> </div>
<div className="flex-1">{t('Special Follow')}</div> <div className="flex-1">{t('Special Follow')}</div>
@ -74,7 +74,7 @@ export default function FeedSwitcher({ close }: { close?: () => void }) {
action={ action={
<SecondaryPageLink <SecondaryPageLink
to={toRelaySettings()} to={toRelaySettings()}
className="flex items-center gap-1 text-xs text-primary hover:text-primary-hover transition-colors font-medium" className="flex items-center gap-1 text-xs font-medium text-primary transition-colors hover:text-primary-hover"
onClick={() => close?.()} onClick={() => close?.()}
> >
<Settings2 className="size-3" /> <Settings2 className="size-3" />
@ -104,9 +104,9 @@ export default function FeedSwitcher({ close }: { close?: () => void }) {
close?.() close?.()
}} }}
> >
<div className="flex gap-3 items-center w-full"> <div className="flex w-full items-center gap-3">
<RelayIcon url={relay} className="shrink-0" /> <RelayIcon url={relay} className="shrink-0" />
<div className="flex-1 w-0 truncate">{simplifyUrl(relay)}</div> <div className="w-0 flex-1 truncate">{simplifyUrl(relay)}</div>
</div> </div>
</FeedSwitcherItem> </FeedSwitcherItem>
))} ))}
@ -119,8 +119,8 @@ export default function FeedSwitcher({ close }: { close?: () => void }) {
function SectionHeader({ title, action }: { title: string; action?: React.ReactNode }) { function SectionHeader({ title, action }: { title: string; action?: React.ReactNode }) {
return ( return (
<div className="flex justify-between items-center px-1 py-1"> <div className="flex items-center justify-between px-1 py-1">
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider"> <h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
{title} {title}
</h3> </h3>
{action} {action}
@ -142,19 +142,19 @@ function FeedSwitcherItem({
return ( return (
<div <div
className={cn( className={cn(
'group relative w-full border rounded-lg px-3 py-2.5 transition-all duration-200', 'group relative w-full rounded-lg border px-3 py-2.5 transition-all duration-200',
disabled && 'opacity-50 pointer-events-none', disabled && 'pointer-events-none opacity-50',
isActive isActive
? 'border-primary bg-primary/5 shadow-sm' ? 'border-primary bg-primary/5 shadow-sm'
: 'border-border hover:border-primary/50 hover:bg-accent/50 clickable' : 'clickable border-border hover:border-primary/50 hover:bg-accent/50'
)} )}
onClick={() => { onClick={() => {
if (disabled) return if (disabled) return
onClick() onClick()
}} }}
> >
<div className="flex justify-between items-center gap-2"> <div className="flex items-center justify-between gap-2">
<div className="font-medium flex-1 min-w-0">{children}</div> <div className="min-w-0 flex-1 font-medium">{children}</div>
</div> </div>
</div> </div>
) )

View file

@ -53,7 +53,7 @@ export default function FollowButton({ pubkey }: { pubkey: string }) {
<AlertDialog> <AlertDialog>
<AlertDialogTrigger asChild> <AlertDialogTrigger asChild>
<Button <Button
className="rounded-full min-w-28" className="min-w-28 rounded-full"
variant={hover ? 'destructive' : 'secondary'} variant={hover ? 'destructive' : 'secondary'}
disabled={updating} disabled={updating}
onMouseEnter={() => setHover(true)} onMouseEnter={() => setHover(true)}
@ -85,7 +85,7 @@ export default function FollowButton({ pubkey }: { pubkey: string }) {
</AlertDialog> </AlertDialog>
</div> </div>
) : ( ) : (
<Button className="rounded-full min-w-28" onClick={handleFollow} disabled={updating}> <Button className="min-w-28 rounded-full" onClick={handleFollow} disabled={updating}>
{updating ? <Loader className="animate-spin" /> : t('Follow')} {updating ? <Loader className="animate-spin" /> : t('Follow')}
</Button> </Button>
) )

View file

@ -16,7 +16,7 @@ export default function FollowingBadge({ pubkey, userId }: { pubkey?: string; us
if (!isFollowing) return null if (!isFollowing) return null
return ( return (
<div className="rounded-full bg-muted px-2 py-0.5 flex items-center" title={t('Following')}> <div className="flex items-center rounded-full bg-muted px-2 py-0.5" title={t('Following')}>
<UserRoundCheck className="!size-3" /> <UserRoundCheck className="!size-3" />
</div> </div>
) )

View file

@ -64,7 +64,7 @@ export default function FollowingFavoriteRelayList() {
{showCount < relays.length && <div ref={bottomRef} />} {showCount < relays.length && <div ref={bottomRef} />}
{loading && <RelaySimpleInfoSkeleton className="p-4" />} {loading && <RelaySimpleInfoSkeleton className="p-4" />}
{!loading && ( {!loading && (
<div className="text-center text-muted-foreground text-sm mt-2"> <div className="mt-2 text-center text-sm text-muted-foreground">
{relays.length === 0 ? t('no relays found') : t('no more relays')} {relays.length === 0 ? t('no relays found') : t('no more relays')}
</div> </div>
)} )}
@ -81,7 +81,7 @@ function RelayItem({ url, users }: { url: string; users: string[] }) {
key={url} key={url}
relayInfo={relayInfo} relayInfo={relayInfo}
users={users} users={users}
className="clickable p-4 border-b" className="clickable border-b p-4"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toRelay(url)) push(toRelay(url))

View file

@ -87,7 +87,7 @@ export default function HighlightButton({ onHighlight, containerRef }: Highlight
return ( return (
<div <div
className="fixed z-50 animate-in fade-in-0 slide-in-from-bottom-4 duration-200" className="fixed z-50 duration-200 animate-in fade-in-0 slide-in-from-bottom-4"
style={{ style={{
top: `${position.top}px`, top: `${position.top}px`,
left: `${position.left}px` left: `${position.left}px`
@ -97,7 +97,7 @@ export default function HighlightButton({ onHighlight, containerRef }: Highlight
ref={buttonRef} ref={buttonRef}
size="sm" size="sm"
variant="default" variant="default"
className="shadow-lg gap-2 -translate-x-1/2" className="-translate-x-1/2 gap-2 shadow-lg"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
onHighlight(selectedText) onHighlight(selectedText)

View file

@ -79,7 +79,7 @@ export default function Image({
<img <img
src={`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${dim.width}' height='${dim.height}'%3E%3C/svg%3E`} src={`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${dim.width}' height='${dim.height}'%3E%3C/svg%3E`}
className={cn( className={cn(
'object-cover transition-opacity pointer-events-none w-full h-full', 'pointer-events-none h-full w-full object-cover transition-opacity',
className className
)} )}
alt="" alt=""
@ -91,7 +91,7 @@ export default function Image({
<ThumbHashPlaceholder <ThumbHashPlaceholder
thumbHash={thumbHash} thumbHash={thumbHash}
className={cn( className={cn(
'w-full h-full transition-opacity', 'h-full w-full transition-opacity',
isLoading ? 'opacity-100' : 'opacity-0' isLoading ? 'opacity-100' : 'opacity-0'
)} )}
/> />
@ -99,14 +99,14 @@ export default function Image({
<BlurHashCanvas <BlurHashCanvas
blurHash={blurHash} blurHash={blurHash}
className={cn( className={cn(
'w-full h-full transition-opacity', 'h-full w-full transition-opacity',
isLoading ? 'opacity-100' : 'opacity-0' isLoading ? 'opacity-100' : 'opacity-0'
)} )}
/> />
) : ( ) : (
<Skeleton <Skeleton
className={cn( className={cn(
'w-full h-full transition-opacity', 'h-full w-full transition-opacity',
isLoading ? 'opacity-100' : 'opacity-0', isLoading ? 'opacity-100' : 'opacity-0',
classNames.skeleton classNames.skeleton
)} )}
@ -124,8 +124,8 @@ export default function Image({
onLoad={handleLoad} onLoad={handleLoad}
onError={handleError} onError={handleError}
className={cn( className={cn(
'object-cover transition-opacity pointer-events-none w-full h-full', 'pointer-events-none h-full w-full object-cover transition-opacity',
isLoading ? 'opacity-0 absolute inset-0' : '', isLoading ? 'absolute inset-0 opacity-0' : '',
className className
)} )}
/> />
@ -137,12 +137,12 @@ export default function Image({
alt={alt} alt={alt}
decoding="async" decoding="async"
loading="lazy" loading="lazy"
className={cn('object-cover w-full h-full transition-opacity', className)} className={cn('h-full w-full object-cover transition-opacity', className)}
/> />
) : ( ) : (
<div <div
className={cn( className={cn(
'object-cover flex flex-col items-center justify-center w-full h-full bg-muted', 'flex h-full w-full flex-col items-center justify-center bg-muted object-cover',
className, className,
classNames.errorPlaceholder classNames.errorPlaceholder
)} )}
@ -188,7 +188,7 @@ function BlurHashCanvas({ blurHash, className = '' }: { blurHash: string; classN
ref={canvasRef} ref={canvasRef}
width={blurHashWidth} width={blurHashWidth}
height={blurHashHeight} height={blurHashHeight}
className={cn('w-full h-full object-cover rounded-xl', className)} className={cn('h-full w-full rounded-xl object-cover', className)}
style={{ style={{
imageRendering: 'auto', imageRendering: 'auto',
filter: 'blur(0.5px)' filter: 'blur(0.5px)'
@ -218,7 +218,7 @@ function ThumbHashPlaceholder({
return ( return (
<div <div
className={cn('w-full h-full object-cover rounded-lg', className)} className={cn('h-full w-full rounded-lg object-cover', className)}
style={{ style={{
backgroundImage: `url(${dataUrl})`, backgroundImage: `url(${dataUrl})`,
backgroundSize: 'cover', backgroundSize: 'cover',

View file

@ -94,7 +94,7 @@ export default function ImageGallery({
<ImageWithLightbox <ImageWithLightbox
key={i} key={i}
image={image} image={image}
className="max-h-[80vh] sm:max-h-[50vh] object-contain" className="max-h-[80vh] object-contain sm:max-h-[50vh]"
classNames={{ classNames={{
wrapper: cn('w-fit max-w-full border', className) wrapper: cn('w-fit max-w-full border', className)
}} }}
@ -107,7 +107,7 @@ export default function ImageGallery({
imageContent = ( imageContent = (
<Image <Image
key={0} key={0}
className="max-h-[80vh] sm:max-h-[50vh] object-contain" className="max-h-[80vh] object-contain sm:max-h-[50vh]"
classNames={{ classNames={{
errorPlaceholder: 'aspect-square h-[30vh]', errorPlaceholder: 'aspect-square h-[30vh]',
wrapper: 'cursor-zoom-in border' wrapper: 'cursor-zoom-in border'
@ -118,7 +118,7 @@ export default function ImageGallery({
) )
} else if (displayImages.length === 2 || displayImages.length === 4) { } else if (displayImages.length === 2 || displayImages.length === 4) {
imageContent = ( imageContent = (
<div className="grid grid-cols-2 gap-2 w-full"> <div className="grid w-full grid-cols-2 gap-2">
{displayImages.map((image, i) => ( {displayImages.map((image, i) => (
<Image <Image
key={i} key={i}
@ -132,7 +132,7 @@ export default function ImageGallery({
) )
} else { } else {
imageContent = ( imageContent = (
<div className="grid grid-cols-3 gap-2 w-full"> <div className="grid w-full grid-cols-3 gap-2">
{displayImages.map((image, i) => ( {displayImages.map((image, i) => (
<Image <Image
key={i} key={i}

View file

@ -44,7 +44,7 @@ export default function ImageWithLightbox({
if (!display) { if (!display) {
return ( return (
<div <div
className="text-primary hover:underline truncate w-fit cursor-pointer" className="w-fit cursor-pointer truncate text-primary hover:underline"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
setDisplay(true) setDisplay(true)

View file

@ -25,7 +25,7 @@ export default function InfoCard({
variant?: 'info' | 'success' | 'alert' variant?: 'info' | 'success' | 'alert'
}) { }) {
return ( return (
<div className={cn('p-3 rounded-lg text-sm [&_svg]:size-4', VARIANT_STYLES[variant])}> <div className={cn('rounded-lg p-3 text-sm [&_svg]:size-4', VARIANT_STYLES[variant])}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{icon ?? ICON_MAP[variant]} {icon ?? ICON_MAP[variant]}
<div className="font-medium">{title}</div> <div className="font-medium">{title}</div>

View file

@ -95,7 +95,7 @@ export default function KindFilter({
> >
<ListFilter size={16} /> <ListFilter size={16} />
{isDifferentFromSaved && ( {isDifferentFromSaved && (
<div className="absolute size-2 rounded-full bg-primary left-7 top-2 ring-2 ring-background" /> <div className="absolute left-7 top-2 size-2 rounded-full bg-primary ring-2 ring-background" />
)} )}
</Button> </Button>
) )
@ -109,7 +109,7 @@ export default function KindFilter({
<div <div
key={label} key={label}
className={cn( className={cn(
'cursor-pointer grid gap-1.5 rounded-lg border px-4 py-3', 'grid cursor-pointer gap-1.5 rounded-lg border px-4 py-3',
checked ? 'border-primary/60 bg-primary/5' : 'clickable' checked ? 'border-primary/60 bg-primary/5' : 'clickable'
)} )}
onClick={() => { onClick={() => {
@ -122,14 +122,14 @@ export default function KindFilter({
} }
}} }}
> >
<p className="leading-none font-medium">{t(label)}</p> <p className="font-medium leading-none">{t(label)}</p>
<p className="text-muted-foreground text-xs">kind {kindGroup.join(', ')}</p> <p className="text-xs text-muted-foreground">kind {kindGroup.join(', ')}</p>
</div> </div>
) )
})} })}
</div> </div>
<div className="grid grid-cols-3 gap-2 mt-4"> <div className="mt-4 grid grid-cols-3 gap-2">
<Button <Button
variant="secondary" variant="secondary"
onClick={() => { onClick={() => {
@ -155,7 +155,7 @@ export default function KindFilter({
</Button> </Button>
</div> </div>
<Label className="flex items-center gap-2 cursor-pointer mt-4"> <Label className="mt-4 flex cursor-pointer items-center gap-2">
<Checkbox <Checkbox
id="persistent-filter" id="persistent-filter"
checked={isPersistent} checked={isPersistent}

View file

@ -4,7 +4,7 @@ export function LoadingBar({ className }: { className?: string }) {
return ( return (
<div className={cn('h-0.5 w-full overflow-hidden', className)}> <div className={cn('h-0.5 w-full overflow-hidden', className)}>
<div <div
className="h-full w-full bg-gradient-to-r from-primary/40 from-25% via-primary via-50% to-primary/40 to-75% animate-shimmer" className="h-full w-full animate-shimmer bg-gradient-to-r from-primary/40 from-25% via-primary via-50% to-primary/40 to-75%"
style={{ style={{
backgroundSize: '400% 100%' backgroundSize: '400% 100%'
}} }}

View file

@ -17,7 +17,7 @@ export default function LoginDialog({
return ( return (
<Drawer open={open} onOpenChange={setOpen}> <Drawer open={open} onOpenChange={setOpen}>
<DrawerContent className="max-h-[90vh]"> <DrawerContent className="max-h-[90vh]">
<div className="flex flex-col p-4 gap-4 overflow-auto"> <div className="flex flex-col gap-4 overflow-auto p-4">
<AccountManager close={() => setOpen(false)} /> <AccountManager close={() => setOpen(false)} />
</div> </div>
</DrawerContent> </DrawerContent>
@ -27,7 +27,7 @@ export default function LoginDialog({
return ( return (
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="w-[520px] max-h-[90vh] py-8 overflow-auto"> <DialogContent className="max-h-[90vh] w-[520px] overflow-auto py-8">
<AccountManager close={() => setOpen(false)} /> <AccountManager close={() => setOpen(false)} />
</DialogContent> </DialogContent>
</Dialog> </Dialog>

View file

@ -38,21 +38,21 @@ export default function MailboxRelay({
return ( return (
<div ref={setNodeRef} style={style} className="flex items-center justify-between"> <div ref={setNodeRef} style={style} className="flex items-center justify-between">
<div className="flex items-center gap-2 flex-1 w-0"> <div className="flex w-0 flex-1 items-center gap-2">
<div <div
{...attributes} {...attributes}
{...listeners} {...listeners}
className="cursor-grab active:cursor-grabbing p-2 hover:bg-muted rounded touch-none" className="cursor-grab touch-none rounded p-2 hover:bg-muted active:cursor-grabbing"
style={{ touchAction: 'none' }} style={{ touchAction: 'none' }}
> >
<GripVertical size={16} className="text-muted-foreground" /> <GripVertical size={16} className="text-muted-foreground" />
</div> </div>
<div <div
className="flex items-center gap-2 flex-1 w-0 cursor-pointer" className="flex w-0 flex-1 cursor-pointer items-center gap-2"
onClick={() => push(toRelay(mailboxRelay.url))} onClick={() => push(toRelay(mailboxRelay.url))}
> >
<RelayIcon url={mailboxRelay.url} /> <RelayIcon url={mailboxRelay.url} />
<div className="truncate flex-1 w-0">{mailboxRelay.url}</div> <div className="w-0 flex-1 truncate">{mailboxRelay.url}</div>
</div> </div>
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
@ -72,7 +72,7 @@ export default function MailboxRelay({
<CircleX <CircleX
size={16} size={16}
onClick={() => removeMailboxRelay(mailboxRelay.url)} onClick={() => removeMailboxRelay(mailboxRelay.url)}
className="text-muted-foreground hover:text-destructive clickable" className="clickable text-muted-foreground hover:text-destructive"
/> />
</div> </div>
</div> </div>

View file

@ -46,7 +46,7 @@ export default function NewMailboxRelayInput({
/> />
<Button onClick={save}>{t('Add')}</Button> <Button onClick={save}>{t('Add')}</Button>
</div> </div>
{newRelayUrlError && <div className="text-destructive text-xs mt-1">{newRelayUrlError}</div>} {newRelayUrlError && <div className="mt-1 text-xs text-destructive">{newRelayUrlError}</div>}
</div> </div>
) )
} }

View file

@ -71,7 +71,7 @@ export default function MailboxSetting() {
if (!pubkey) { if (!pubkey) {
return ( return (
<div className="flex flex-col w-full items-center"> <div className="flex w-full flex-col items-center">
<Button size="lg" onClick={() => checkLogin()}> <Button size="lg" onClick={() => checkLogin()}>
{t('Login to set')} {t('Login to set')}
</Button> </Button>
@ -109,7 +109,7 @@ export default function MailboxSetting() {
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="text-xs text-muted-foreground space-y-1"> <div className="space-y-1 text-xs text-muted-foreground">
<div>{t('read relays description')}</div> <div>{t('read relays description')}</div>
<div>{t('write relays description')}</div> <div>{t('write relays description')}</div>
<div>{t('read & write relays notice')}</div> <div>{t('read & write relays notice')}</div>

View file

@ -72,7 +72,7 @@ export default function MediaPlayer({
if (!mustLoad && !display) { if (!mustLoad && !display) {
return ( return (
<div <div
className="text-primary hover:underline truncate w-fit cursor-pointer" className="w-fit cursor-pointer truncate text-primary hover:underline"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
setDisplay(true) setDisplay(true)

View file

@ -91,7 +91,7 @@ export default function MuteButton({ pubkey }: { pubkey: string }) {
<DrawerContent> <DrawerContent>
<div className="py-2"> <div className="py-2">
<Button <Button
className="w-full p-6 justify-start text-destructive text-lg gap-4 [&_svg]:size-5 focus:text-destructive" className="w-full justify-start gap-4 p-6 text-lg text-destructive focus:text-destructive [&_svg]:size-5"
variant="ghost" variant="ghost"
onClick={(e) => handleMute(e, true)} onClick={(e) => handleMute(e, true)}
disabled={updating || changing} disabled={updating || changing}
@ -99,7 +99,7 @@ export default function MuteButton({ pubkey }: { pubkey: string }) {
{updating ? <Loader className="animate-spin" /> : t('Mute user privately')} {updating ? <Loader className="animate-spin" /> : t('Mute user privately')}
</Button> </Button>
<Button <Button
className="w-full p-6 justify-start text-destructive text-lg gap-4 [&_svg]:size-5 focus:text-destructive" className="w-full justify-start gap-4 p-6 text-lg text-destructive focus:text-destructive [&_svg]:size-5"
variant="ghost" variant="ghost"
onClick={(e) => handleMute(e, false)} onClick={(e) => handleMute(e, false)}
disabled={updating || changing} disabled={updating || changing}

View file

@ -37,7 +37,7 @@ export default function NewNotesButton({
{newEvents.length > 0 && ( {newEvents.length > 0 && (
<div <div
className={cn( className={cn(
'w-full flex justify-center z-40 pointer-events-none', 'pointer-events-none z-40 flex w-full justify-center',
enableSingleColumnLayout ? 'sticky' : 'absolute' enableSingleColumnLayout ? 'sticky' : 'absolute'
)} )}
style={{ style={{
@ -48,10 +48,10 @@ export default function NewNotesButton({
> >
<Button <Button
onClick={onClick} onClick={onClick}
className="group rounded-full h-fit py-2 pl-2 pr-3 hover:bg-primary-hover pointer-events-auto" className="group pointer-events-auto h-fit rounded-full py-2 pl-2 pr-3 hover:bg-primary-hover"
> >
{pubkeys.length > 0 && ( {pubkeys.length > 0 && (
<div className="*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale"> <div className="flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background *:data-[slot=avatar]:grayscale">
{pubkeys.map((pubkey) => ( {pubkeys.map((pubkey) => (
<SimpleUserAvatar key={pubkey} userId={pubkey} size="small" /> <SimpleUserAvatar key={pubkey} userId={pubkey} size="small" />
))} ))}

View file

@ -29,24 +29,24 @@ export default function Nip05({ pubkey, append }: { pubkey: string; append?: str
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
{nip05Name !== '_' ? ( {nip05Name !== '_' ? (
<span className="text-sm text-muted-foreground truncate">@{nip05Name}</span> <span className="truncate text-sm text-muted-foreground">@{nip05Name}</span>
) : null} ) : null}
{nip05IsVerified ? ( {nip05IsVerified ? (
<Favicon <Favicon
domain={nip05Domain} domain={nip05Domain}
className="w-3.5 h-3.5 rounded-full shrink-0" className="h-3.5 w-3.5 shrink-0 rounded-full"
fallback={<BadgeCheck className="text-primary shrink-0" />} fallback={<BadgeCheck className="shrink-0 text-primary" />}
/> />
) : ( ) : (
<BadgeAlert className="text-muted-foreground shrink-0" /> <BadgeAlert className="shrink-0 text-muted-foreground" />
)} )}
<SecondaryPageLink <SecondaryPageLink
to={toNoteList({ domain: nip05Domain })} to={toNoteList({ domain: nip05Domain })}
className={`hover:underline truncate text-sm ${nip05IsVerified ? 'text-primary' : 'text-muted-foreground'}`} className={`truncate text-sm hover:underline ${nip05IsVerified ? 'text-primary' : 'text-muted-foreground'}`}
> >
{nip05Domain} {nip05Domain}
</SecondaryPageLink> </SecondaryPageLink>
{append && <span className="text-sm text-muted-foreground truncate">{append}</span>} {append && <span className="truncate text-sm text-muted-foreground">{append}</span>}
</div> </div>
) )
} }

View file

@ -4,7 +4,7 @@ export default function NotFound() {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<div className="text-muted-foreground w-full h-full flex flex-col items-center justify-center gap-2"> <div className="flex h-full w-full flex-col items-center justify-center gap-2 text-muted-foreground">
<div>{t('Lost in the void')} 🌌</div> <div>{t('Lost in the void')} 🌌</div>
<div>(404)</div> <div>(404)</div>
</div> </div>

View file

@ -16,11 +16,11 @@ export default function CommunityDefinition({
const metadata = useMemo(() => getCommunityDefinitionFromEvent(event), [event]) const metadata = useMemo(() => getCommunityDefinitionFromEvent(event), [event])
const communityNameComponent = ( const communityNameComponent = (
<div className="text-xl font-semibold line-clamp-1">{metadata.name}</div> <div className="line-clamp-1 text-xl font-semibold">{metadata.name}</div>
) )
const communityDescriptionComponent = metadata.description && ( const communityDescriptionComponent = metadata.description && (
<div className="text-sm text-muted-foreground line-clamp-2">{metadata.description}</div> <div className="line-clamp-2 text-sm text-muted-foreground">{metadata.description}</div>
) )
return ( return (
@ -29,16 +29,16 @@ export default function CommunityDefinition({
{metadata.image && autoLoadMedia && ( {metadata.image && autoLoadMedia && (
<Image <Image
image={{ url: metadata.image, pubkey: event.pubkey }} image={{ url: metadata.image, pubkey: event.pubkey }}
className="aspect-square bg-foreground h-20" className="aspect-square h-20 bg-foreground"
hideIfError hideIfError
/> />
)} )}
<div className="flex-1 w-0 space-y-1"> <div className="w-0 flex-1 space-y-1">
{communityNameComponent} {communityNameComponent}
{communityDescriptionComponent} {communityDescriptionComponent}
</div> </div>
</div> </div>
<ClientSelect className="w-full mt-2" event={event} /> <ClientSelect className="mt-2 w-full" event={event} />
</div> </div>
) )
} }

View file

@ -44,7 +44,7 @@ export default function EmojiPack({ event, className }: { event: Event; classNam
return ( return (
<div className={className}> <div className={className}>
<div className="flex items-center justify-between mb-2"> <div className="mb-2 flex items-center justify-between">
<h3 className="text-2xl font-semibold">{title}</h3> <h3 className="text-2xl font-semibold">{title}</h3>
{accountPubkey && ( {accountPubkey && (
<Button <Button
@ -55,7 +55,7 @@ export default function EmojiPack({ event, className }: { event: Event; classNam
className="shrink-0" className="shrink-0"
> >
{updating ? ( {updating ? (
<Loader className="animate-spin mr-1" /> <Loader className="mr-1 animate-spin" />
) : isCollected ? ( ) : isCollected ? (
<CheckIcon /> <CheckIcon />
) : ( ) : (

View file

@ -22,11 +22,11 @@ export default function FollowPack({ event, className }: { event: Event; classNa
return ( return (
<div className={className}> <div className={className}>
<div className="flex items-start gap-2 mb-2"> <div className="mb-2 flex items-start gap-2">
{image && ( {image && (
<Image <Image
image={{ url: image, pubkey: event.pubkey }} image={{ url: image, pubkey: event.pubkey }}
className="w-24 h-20 object-cover" className="h-20 w-24 object-cover"
classNames={{ classNames={{
wrapper: 'w-24 h-20 flex-shrink-0', wrapper: 'w-24 h-20 flex-shrink-0',
errorPlaceholder: 'w-24 h-20' errorPlaceholder: 'w-24 h-20'
@ -34,15 +34,15 @@ export default function FollowPack({ event, className }: { event: Event; classNa
hideIfError hideIfError
/> />
)} )}
<div className="flex-1 min-w-0"> <div className="min-w-0 flex-1">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<h3 className="text-xl font-semibold mb-1 truncate">{title}</h3> <h3 className="mb-1 truncate text-xl font-semibold">{title}</h3>
<span className="text-xs text-muted-foreground shrink-0"> <span className="shrink-0 text-xs text-muted-foreground">
{t('n users', { count: pubkeys.length })} {t('n users', { count: pubkeys.length })}
</span> </span>
</div> </div>
{description && ( {description && (
<p className="text-sm text-muted-foreground line-clamp-2">{description}</p> <p className="line-clamp-2 text-sm text-muted-foreground">{description}</p>
)} )}
</div> </div>
</div> </div>

View file

@ -18,11 +18,11 @@ export default function GroupMetadata({
const metadata = useMemo(() => getGroupMetadataFromEvent(event), [event]) const metadata = useMemo(() => getGroupMetadataFromEvent(event), [event])
const groupNameComponent = ( const groupNameComponent = (
<div className="text-xl font-semibold line-clamp-1">{metadata.name}</div> <div className="line-clamp-1 text-xl font-semibold">{metadata.name}</div>
) )
const groupAboutComponent = metadata.about && ( const groupAboutComponent = metadata.about && (
<div className="text-sm text-muted-foreground line-clamp-2">{metadata.about}</div> <div className="line-clamp-2 text-sm text-muted-foreground">{metadata.about}</div>
) )
return ( return (
@ -31,16 +31,16 @@ export default function GroupMetadata({
{metadata.picture && autoLoadMedia && ( {metadata.picture && autoLoadMedia && (
<Image <Image
image={{ url: metadata.picture, pubkey: event.pubkey }} image={{ url: metadata.picture, pubkey: event.pubkey }}
className="aspect-square bg-foreground h-20" className="aspect-square h-20 bg-foreground"
hideIfError hideIfError
/> />
)} )}
<div className="flex-1 w-0 space-y-1"> <div className="w-0 flex-1 space-y-1">
{groupNameComponent} {groupNameComponent}
{groupAboutComponent} {groupAboutComponent}
</div> </div>
</div> </div>
<ClientSelect className="w-full mt-2" event={event} originalNoteId={originalNoteId} /> <ClientSelect className="mt-2 w-full" event={event} originalNoteId={originalNoteId} />
</div> </div>
) )
} }

View file

@ -21,12 +21,12 @@ export default function Highlight({ event, className }: { event: Event; classNam
) )
return ( return (
<div className={cn('text-wrap break-words whitespace-pre-wrap space-y-4', className)}> <div className={cn('space-y-4 whitespace-pre-wrap text-wrap break-words', className)}>
{comment && <Content event={createFakeEvent({ content: comment, tags: event.tags })} />} {comment && <Content event={createFakeEvent({ content: comment, tags: event.tags })} />}
<div className="flex gap-4"> <div className="flex gap-4">
<div className="w-1 flex-shrink-0 my-1 bg-primary/60 rounded-md" /> <div className="my-1 w-1 flex-shrink-0 rounded-md bg-primary/60" />
<div <div
className="italic whitespace-pre-line" className="whitespace-pre-line italic"
style={{ style={{
overflowWrap: 'anywhere' overflowWrap: 'anywhere'
}} }}
@ -112,7 +112,7 @@ function HighlightSource({ event }: { event: Event }) {
{t('From')}{' '} {t('From')}{' '}
<ExternalLink <ExternalLink
url={sourceTag[1]} url={sourceTag[1]}
className="underline italic text-muted-foreground hover:text-foreground" className="italic text-muted-foreground underline hover:text-foreground"
/> />
</div> </div>
) )
@ -124,7 +124,7 @@ function HighlightSource({ event }: { event: Event }) {
{pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />} {pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />}
{referenceEventId && ( {referenceEventId && (
<div <div
className="truncate underline pointer-events-auto cursor-pointer hover:text-foreground" className="pointer-events-auto cursor-pointer truncate underline hover:text-foreground"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toNote(referenceEvent ?? referenceEventId)) push(toNote(referenceEvent ?? referenceEventId))

View file

@ -23,14 +23,14 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
<Badge variant="secondary">{metadata.status}</Badge> <Badge variant="secondary">{metadata.status}</Badge>
)) ))
const titleComponent = <div className="text-xl font-semibold line-clamp-1">{metadata.title}</div> const titleComponent = <div className="line-clamp-1 text-xl font-semibold">{metadata.title}</div>
const summaryComponent = metadata.summary && ( const summaryComponent = metadata.summary && (
<div className="text-sm text-muted-foreground line-clamp-4">{metadata.summary}</div> <div className="line-clamp-4 text-sm text-muted-foreground">{metadata.summary}</div>
) )
const tagsComponent = metadata.tags.length > 0 && ( const tagsComponent = metadata.tags.length > 0 && (
<div className="flex gap-1 flex-wrap"> <div className="flex flex-wrap gap-1">
{metadata.tags.map((tag) => ( {metadata.tags.map((tag) => (
<Badge key={tag} variant="secondary"> <Badge key={tag} variant="secondary">
{tag} {tag}
@ -45,7 +45,7 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
{metadata.image && autoLoadMedia && ( {metadata.image && autoLoadMedia && (
<Image <Image
image={{ url: metadata.image, pubkey: event.pubkey }} image={{ url: metadata.image, pubkey: event.pubkey }}
className="w-full aspect-video" className="aspect-video w-full"
hideIfError hideIfError
/> />
)} )}
@ -54,7 +54,7 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
{liveStatusComponent} {liveStatusComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}
<ClientSelect className="w-full mt-2" event={event} /> <ClientSelect className="mt-2 w-full" event={event} />
</div> </div>
</div> </div>
) )
@ -66,18 +66,18 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
{metadata.image && autoLoadMedia && ( {metadata.image && autoLoadMedia && (
<Image <Image
image={{ url: metadata.image, pubkey: event.pubkey }} image={{ url: metadata.image, pubkey: event.pubkey }}
className="aspect-[4/3] xl:aspect-video bg-foreground h-44" className="aspect-[4/3] h-44 bg-foreground xl:aspect-video"
hideIfError hideIfError
/> />
)} )}
<div className="flex-1 w-0 space-y-1"> <div className="w-0 flex-1 space-y-1">
{titleComponent} {titleComponent}
{liveStatusComponent} {liveStatusComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}
</div> </div>
</div> </div>
<ClientSelect className="w-full mt-2" event={event} /> <ClientSelect className="mt-2 w-full" event={event} />
</div> </div>
) )
} }

View file

@ -43,7 +43,7 @@ export default function LongFormArticle({
return ( return (
<SecondaryPageLink <SecondaryPageLink
to={toNote(href)} to={toNote(href)}
className="break-words underline text-foreground" className="break-words text-foreground underline"
> >
{children} {children}
</SecondaryPageLink> </SecondaryPageLink>
@ -53,7 +53,7 @@ export default function LongFormArticle({
return ( return (
<SecondaryPageLink <SecondaryPageLink
to={toProfile(href)} to={toProfile(href)}
className="break-words underline text-foreground" className="break-words text-foreground underline"
> >
{children} {children}
</SecondaryPageLink> </SecondaryPageLink>
@ -65,7 +65,7 @@ export default function LongFormArticle({
href={href} href={href}
target="_blank" target="_blank"
rel="noreferrer noopener" rel="noreferrer noopener"
className="break-words inline-flex items-baseline gap-1" className="inline-flex items-baseline gap-1 break-words"
> >
{children} <ExternalLink className="size-3" /> {children} <ExternalLink className="size-3" />
</a> </a>
@ -73,11 +73,11 @@ export default function LongFormArticle({
}, },
p: (props) => <p {...props} className="break-words" />, p: (props) => <p {...props} className="break-words" />,
div: (props) => <div {...props} className="break-words" />, div: (props) => <div {...props} className="break-words" />,
code: (props) => <code {...props} className="break-words whitespace-pre-wrap" />, code: (props) => <code {...props} className="whitespace-pre-wrap break-words" />,
img: (props) => ( img: (props) => (
<ImageWithLightbox <ImageWithLightbox
image={{ url: props.src || '', pubkey: event.pubkey }} image={{ url: props.src || '', pubkey: event.pubkey }}
className="max-h-[80vh] sm:max-h-[50vh] object-contain my-0" className="my-0 max-h-[80vh] object-contain sm:max-h-[50vh]"
classNames={{ classNames={{
wrapper: 'w-fit max-w-full' wrapper: 'w-fit max-w-full'
}} }}
@ -91,7 +91,7 @@ export default function LongFormArticle({
<> <>
<div <div
ref={contentRef} ref={contentRef}
className={`prose prose-zinc max-w-none dark:prose-invert break-words overflow-wrap-anywhere ${className || ''}`} className={`overflow-wrap-anywhere prose prose-zinc max-w-none break-words dark:prose-invert ${className || ''}`}
> >
<h1 className="break-words">{metadata.title}</h1> <h1 className="break-words">{metadata.title}</h1>
{metadata.summary && ( {metadata.summary && (
@ -102,7 +102,7 @@ export default function LongFormArticle({
{metadata.image && ( {metadata.image && (
<ImageWithLightbox <ImageWithLightbox
image={{ url: metadata.image, pubkey: event.pubkey }} image={{ url: metadata.image, pubkey: event.pubkey }}
className="w-full aspect-[3/1] object-cover my-0" className="my-0 aspect-[3/1] w-full object-cover"
/> />
)} )}
<Markdown <Markdown
@ -118,12 +118,12 @@ export default function LongFormArticle({
{event.content} {event.content}
</Markdown> </Markdown>
{metadata.tags.length > 0 && ( {metadata.tags.length > 0 && (
<div className="flex gap-2 flex-wrap pb-2"> <div className="flex flex-wrap gap-2 pb-2">
{metadata.tags.map((tag) => ( {metadata.tags.map((tag) => (
<div <div
key={tag} key={tag}
title={tag} title={tag}
className="flex items-center rounded-full px-3 bg-muted text-muted-foreground max-w-44 cursor-pointer hover:bg-accent hover:text-accent-foreground" className="flex max-w-44 cursor-pointer items-center rounded-full bg-muted px-3 text-muted-foreground hover:bg-accent hover:text-accent-foreground"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] })) push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] }))

View file

@ -19,14 +19,14 @@ export default function LongFormArticlePreview({
const { autoLoadMedia } = useContentPolicy() const { autoLoadMedia } = useContentPolicy()
const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event]) const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event])
const titleComponent = <div className="text-xl font-semibold line-clamp-2">{metadata.title}</div> const titleComponent = <div className="line-clamp-2 text-xl font-semibold">{metadata.title}</div>
const tagsComponent = metadata.tags.length > 0 && ( const tagsComponent = metadata.tags.length > 0 && (
<div className="flex gap-1 flex-wrap"> <div className="flex flex-wrap gap-1">
{metadata.tags.map((tag) => ( {metadata.tags.map((tag) => (
<div <div
key={tag} key={tag}
className="flex items-center rounded-full text-xs px-2.5 py-0.5 bg-muted text-muted-foreground max-w-32 cursor-pointer hover:bg-accent hover:text-accent-foreground" className="flex max-w-32 cursor-pointer items-center rounded-full bg-muted px-2.5 py-0.5 text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] })) push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] }))
@ -39,7 +39,7 @@ export default function LongFormArticlePreview({
) )
const summaryComponent = metadata.summary && ( const summaryComponent = metadata.summary && (
<div className="text-sm text-muted-foreground line-clamp-4">{metadata.summary}</div> <div className="line-clamp-4 text-sm text-muted-foreground">{metadata.summary}</div>
) )
if (isSmallScreen) { if (isSmallScreen) {
@ -48,7 +48,7 @@ export default function LongFormArticlePreview({
{metadata.image && autoLoadMedia && ( {metadata.image && autoLoadMedia && (
<Image <Image
image={{ url: metadata.image, pubkey: event.pubkey }} image={{ url: metadata.image, pubkey: event.pubkey }}
className="w-full aspect-video" className="aspect-video w-full"
hideIfError hideIfError
/> />
)} )}
@ -67,11 +67,11 @@ export default function LongFormArticlePreview({
{metadata.image && autoLoadMedia && ( {metadata.image && autoLoadMedia && (
<Image <Image
image={{ url: metadata.image, pubkey: event.pubkey }} image={{ url: metadata.image, pubkey: event.pubkey }}
className="aspect-[4/3] xl:aspect-video object-cover bg-foreground h-44" className="aspect-[4/3] h-44 bg-foreground object-cover xl:aspect-video"
hideIfError hideIfError
/> />
)} )}
<div className="flex-1 w-0 space-y-1"> <div className="w-0 flex-1 space-y-1">
{titleComponent} {titleComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}

View file

@ -6,7 +6,7 @@ export default function MutedNote({ show }: { show: () => void }) {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<div className="flex flex-col gap-2 items-center text-muted-foreground font-medium my-4"> <div className="my-4 flex flex-col items-center gap-2 font-medium text-muted-foreground">
<div>{t('This user has been muted')}</div> <div>{t('This user has been muted')}</div>
<Button <Button
onClick={(e) => { onClick={(e) => {

View file

@ -6,7 +6,7 @@ export default function NsfwNote({ show }: { show: () => void }) {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<div className="flex flex-col gap-2 items-center text-muted-foreground font-medium my-4"> <div className="my-4 flex flex-col items-center gap-2 font-medium text-muted-foreground">
<div>{t('🔞 NSFW 🔞')}</div> <div>{t('🔞 NSFW 🔞')}</div>
<Button <Button
onClick={(e) => { onClick={(e) => {

View file

@ -170,7 +170,7 @@ export default function Poll({ event, className }: { event: Event; className?: s
key={option.id} key={option.id}
title={option.label} title={option.label}
className={cn( className={cn(
'relative w-full px-4 py-3 rounded-lg border transition-all flex items-center gap-2 overflow-hidden', 'relative flex w-full items-center gap-2 overflow-hidden rounded-lg border px-4 py-3 transition-all',
canVote ? 'cursor-pointer' : 'cursor-not-allowed', canVote ? 'cursor-pointer' : 'cursor-not-allowed',
canVote && canVote &&
(selectedOptionIds.includes(option.id) (selectedOptionIds.includes(option.id)
@ -184,7 +184,7 @@ export default function Poll({ event, className }: { event: Event; className?: s
disabled={!canVote} disabled={!canVote}
> >
{/* Content */} {/* Content */}
<div className="flex items-center gap-2 flex-1 w-0 z-10"> <div className="z-10 flex w-0 flex-1 items-center gap-2">
<div className={cn('line-clamp-2 text-left', isMax ? 'font-semibold' : '')}> <div className={cn('line-clamp-2 text-left', isMax ? 'font-semibold' : '')}>
{option.label} {option.label}
</div> </div>
@ -195,7 +195,7 @@ export default function Poll({ event, className }: { event: Event; className?: s
{showResults && ( {showResults && (
<div <div
className={cn( className={cn(
'text-muted-foreground shrink-0 z-10', 'z-10 shrink-0 text-muted-foreground',
isMax ? 'font-semibold text-foreground' : '' isMax ? 'font-semibold text-foreground' : ''
)} )}
> >
@ -217,13 +217,13 @@ export default function Poll({ event, className }: { event: Event; className?: s
</div> </div>
{/* Results Summary */} {/* Results Summary */}
<div className="flex justify-between items-center text-sm text-muted-foreground"> <div className="flex items-center justify-between text-sm text-muted-foreground">
<div>{t('{{number}} votes', { number: pollResults?.totalVotes ?? 0 })}</div> <div>{t('{{number}} votes', { number: pollResults?.totalVotes ?? 0 })}</div>
{isLoadingResults && t('Loading...')} {isLoadingResults && t('Loading...')}
{!isLoadingResults && showResults && ( {!isLoadingResults && showResults && (
<div <div
className="hover:underline cursor-pointer" className="cursor-pointer hover:underline"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
fetchResults() fetchResults()

View file

@ -20,7 +20,7 @@ export default function RelayReview({ event, className }: { event: Event; classN
<Stars stars={stars} /> <Stars stars={stars} />
<span className="text-sm text-muted-foreground"></span> <span className="text-sm text-muted-foreground"></span>
<div <div
className="text-sm text-muted-foreground hover:text-foreground hover:underline cursor-pointer truncate" className="cursor-pointer truncate text-sm text-muted-foreground hover:text-foreground hover:underline"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toRelay(url)) push(toRelay(url))

View file

@ -9,7 +9,7 @@ export default function UnknownNote({ event, className }: { event: Event; classN
return ( return (
<div <div
className={cn( className={cn(
'flex flex-col gap-2 items-center text-muted-foreground font-medium my-4', 'my-4 flex flex-col items-center gap-2 font-medium text-muted-foreground',
className className
)} )}
> >

View file

@ -122,14 +122,14 @@ export default function Note({
return ( return (
<div className={className}> <div className={className}>
<div className="flex justify-between items-start gap-2"> <div className="flex items-start justify-between gap-2">
<div className="flex items-center space-x-2 flex-1"> <div className="flex flex-1 items-center space-x-2">
<UserAvatar userId={event.pubkey} size={size === 'small' ? 'medium' : 'normal'} /> <UserAvatar userId={event.pubkey} size={size === 'small' ? 'medium' : 'normal'} />
<div className="flex-1 w-0"> <div className="w-0 flex-1">
<div className="flex gap-2 items-center"> <div className="flex items-center gap-2">
<Username <Username
userId={event.pubkey} userId={event.pubkey}
className={`font-semibold flex truncate ${size === 'small' ? 'text-sm' : ''}`} className={`flex truncate font-semibold ${size === 'small' ? 'text-sm' : ''}`}
skeletonClassName={size === 'small' ? 'h-3' : 'h-4'} skeletonClassName={size === 'small' ? 'h-3' : 'h-4'}
/> />
<FollowingBadge pubkey={event.pubkey} /> <FollowingBadge pubkey={event.pubkey} />
@ -149,7 +149,7 @@ export default function Note({
<div className="flex items-center"> <div className="flex items-center">
<TranslateButton event={event} className={size === 'normal' ? '' : 'pr-0'} /> <TranslateButton event={event} className={size === 'normal' ? '' : 'pr-0'} />
{size === 'normal' && ( {size === 'normal' && (
<NoteOptions event={event} className="py-1 shrink-0 [&_svg]:size-5" /> <NoteOptions event={event} className="shrink-0 py-1 [&_svg]:size-5" />
)} )}
</div> </div>
</div> </div>

View file

@ -37,7 +37,7 @@ export default function MainNoteCard({
<div <div
className={cn( className={cn(
'clickable transition-all duration-200', 'clickable transition-all duration-200',
embedded ? 'p-3 sm:p-4 border rounded-xl bg-card' : 'py-3 hover:bg-accent/30' embedded ? 'rounded-xl border bg-card p-3 sm:p-4' : 'py-3 hover:bg-accent/30'
)} )}
> >
<Collapsible alwaysExpand={embedded}> <Collapsible alwaysExpand={embedded}>

View file

@ -15,7 +15,7 @@ export default function PinnedButton({ event }: { event: NostrEvent }) {
if (event.pubkey !== pubkey) { if (event.pubkey !== pubkey) {
return ( return (
<div className="flex gap-1 text-sm items-center text-primary mb-1 px-4 py-0 h-fit"> <div className="mb-1 flex h-fit items-center gap-1 px-4 py-0 text-sm text-primary">
<Pin size={16} className="shrink-0" /> <Pin size={16} className="shrink-0" />
{t('Pinned')} {t('Pinned')}
</div> </div>
@ -24,7 +24,7 @@ export default function PinnedButton({ event }: { event: NostrEvent }) {
return ( return (
<Button <Button
className="flex gap-1 text-sm text-primary items-center mb-1 px-4 py-0.5 h-fit" className="mb-1 flex h-fit items-center gap-1 px-4 py-0.5 text-sm text-primary"
variant="link" variant="link"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
@ -36,7 +36,7 @@ export default function PinnedButton({ event }: { event: NostrEvent }) {
onMouseLeave={() => setHovered(false)} onMouseLeave={() => setHovered(false)}
> >
{unpinning ? ( {unpinning ? (
<Loader size={16} className="animate-spin shrink-0" /> <Loader size={16} className="shrink-0 animate-spin" />
) : ( ) : (
<Pin size={16} className="shrink-0" /> <Pin size={16} className="shrink-0" />
)} )}

View file

@ -22,19 +22,19 @@ export default function RepostDescription({
if (!reposters?.length) return null if (!reposters?.length) return null
return ( return (
<div className={cn('flex gap-1 text-sm items-center text-muted-foreground mb-1', className)}> <div className={cn('mb-1 flex items-center gap-1 text-sm text-muted-foreground', className)}>
<Repeat2 size={16} className="shrink-0" /> <Repeat2 size={16} className="shrink-0" />
<Username <Username
key={reposters[0]} key={reposters[0]}
userId={reposters[0]} userId={reposters[0]}
className={cn('font-semibold truncate', reposters.length > 1 && 'after:content-[","]')} className={cn('truncate font-semibold', reposters.length > 1 && 'after:content-[","]')}
skeletonClassName="h-3" skeletonClassName="h-3"
/> />
{reposters.length > 1 && ( {reposters.length > 1 && (
<Username <Username
key={reposters[1]} key={reposters[1]}
userId={reposters[1]} userId={reposters[1]}
className={cn('font-semibold truncate', reposters.length === 3 && 'after:content-[","]')} className={cn('truncate font-semibold', reposters.length === 3 && 'after:content-[","]')}
skeletonClassName="h-3" skeletonClassName="h-3"
/> />
)} )}
@ -44,7 +44,7 @@ export default function RepostDescription({
<Username <Username
key={reposters[2]} key={reposters[2]}
userId={reposters[2]} userId={reposters[2]}
className={cn('font-semibold truncate')} className={cn('truncate font-semibold')}
skeletonClassName="h-3" skeletonClassName="h-3"
/> />
) : null} ) : null}
@ -63,7 +63,7 @@ function AndXOthers({ reposters }: { reposters: string[] }) {
{t('and {{x}} others', { x: reposters.length })} {t('and {{x}} others', { x: reposters.length })}
</span> </span>
</HoverCardTrigger> </HoverCardTrigger>
<HoverCardContent className="w-fit max-w-60 flex flex-wrap p-2"> <HoverCardContent className="flex w-fit max-w-60 flex-wrap p-2">
{reposters.map((pubkey) => ( {reposters.map((pubkey) => (
<div key={pubkey} className="p-2"> <div key={pubkey} className="p-2">
<UserAvatar key={pubkey} userId={pubkey} size="small" /> <UserAvatar key={pubkey} userId={pubkey} size="small" />

View file

@ -56,8 +56,8 @@ export function NoteCardLoadingSkeleton({ className }: { className?: string }) {
return ( return (
<div className={cn('px-4 py-3', className)}> <div className={cn('px-4 py-3', className)}>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Skeleton className="w-10 h-10 rounded-full" /> <Skeleton className="h-10 w-10 rounded-full" />
<div className={`flex-1 w-0`}> <div className={`w-0 flex-1`}>
<div className="py-1"> <div className="py-1">
<Skeleton className="h-4 w-16" /> <Skeleton className="h-4 w-16" />
</div> </div>
@ -68,10 +68,10 @@ export function NoteCardLoadingSkeleton({ className }: { className?: string }) {
</div> </div>
<div className="pt-2"> <div className="pt-2">
<div className="my-1"> <div className="my-1">
<Skeleton className="w-full h-4 my-1 mt-2" /> <Skeleton className="my-1 mt-2 h-4 w-full" />
</div> </div>
<div className="my-1"> <div className="my-1">
<Skeleton className="w-2/3 h-4 my-1" /> <Skeleton className="my-1 h-4 w-2/3" />
</div> </div>
</div> </div>
</div> </div>

View file

@ -39,13 +39,13 @@ export function Tabs({
return ( return (
<div className="w-fit"> <div className="w-fit">
<div className="flex relative"> <div className="relative flex">
{TABS.map((tab, index) => ( {TABS.map((tab, index) => (
<div <div
key={tab.value} key={tab.value}
ref={(el) => (tabRefs.current[index] = el)} ref={(el) => (tabRefs.current[index] = el)}
className={cn( className={cn(
`text-center px-4 py-2 font-semibold clickable cursor-pointer rounded-lg`, `clickable cursor-pointer rounded-lg px-4 py-2 text-center font-semibold`,
selectedTab === tab.value ? '' : 'text-muted-foreground' selectedTab === tab.value ? '' : 'text-muted-foreground'
)} )}
onClick={() => onTabChange(tab.value)} onClick={() => onTabChange(tab.value)}
@ -54,7 +54,7 @@ export function Tabs({
</div> </div>
))} ))}
<div <div
className="absolute bottom-0 h-1 bg-primary rounded-full transition-all duration-500" className="absolute bottom-0 h-1 rounded-full bg-primary transition-all duration-500"
style={{ style={{
width: `${indicatorStyle.width}px`, width: `${indicatorStyle.width}px`,
left: `${indicatorStyle.left}px` left: `${indicatorStyle.left}px`

View file

@ -38,9 +38,9 @@ export default function NoteInteractions({ event }: { event: Event }) {
return ( return (
<> <>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<ScrollArea className="flex-1 w-0"> <ScrollArea className="w-0 flex-1">
<Tabs selectedTab={type} onTabChange={setType} /> <Tabs selectedTab={type} onTabChange={setType} />
<ScrollBar orientation="horizontal" className="opacity-0 pointer-events-none" /> <ScrollBar orientation="horizontal" className="pointer-events-none opacity-0" />
</ScrollArea> </ScrollArea>
<Separator orientation="vertical" className="h-6" /> <Separator orientation="vertical" className="h-6" />
<TrustScoreFilter filterId={SPECIAL_TRUST_SCORE_FILTER_ID.INTERACTIONS} /> <TrustScoreFilter filterId={SPECIAL_TRUST_SCORE_FILTER_ID.INTERACTIONS} />

View file

@ -492,12 +492,12 @@ const NoteList = forwardRef<
{shouldShowLoadingIndicator || filtering || initialLoading ? ( {shouldShowLoadingIndicator || filtering || initialLoading ? (
<NoteCardLoadingSkeleton /> <NoteCardLoadingSkeleton />
) : events.length ? ( ) : events.length ? (
<div className="text-center text-sm text-muted-foreground mt-2">{t('no more notes')}</div> <div className="mt-2 text-center text-sm text-muted-foreground">{t('no more notes')}</div>
) : ( ) : (
<div className="flex flex-col items-center justify-center w-full mt-8 gap-4"> <div className="mt-8 flex w-full flex-col items-center justify-center gap-4">
<div className="text-center text-muted-foreground"> <div className="text-center text-muted-foreground">
<div className="text-lg font-medium">{t('No notes found')}</div> <div className="text-lg font-medium">{t('No notes found')}</div>
<div className="text-sm mt-1">{t('Try again later or check your connection')}</div> <div className="mt-1 text-sm">{t('Try again later or check your connection')}</div>
</div> </div>
<Button size="lg" onClick={() => setRefreshCount((count) => count + 1)}> <Button size="lg" onClick={() => setRefreshCount((count) => count + 1)}>
{t('Reload')} {t('Reload')}

View file

@ -40,7 +40,7 @@ export function MobileMenu({
<Button <Button
key={index} key={index}
onClick={action.onClick} onClick={action.onClick}
className={`w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5 ${action.className || ''}`} className={`w-full justify-start gap-4 p-6 text-lg [&_svg]:size-5 ${action.className || ''}`}
variant="ghost" variant="ghost"
> >
<Icon /> <Icon />
@ -52,18 +52,18 @@ export function MobileMenu({
<> <>
<Button <Button
onClick={goBackToMainMenu} onClick={goBackToMainMenu}
className="w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5 mb-2" className="mb-2 w-full justify-start gap-4 p-6 text-lg [&_svg]:size-5"
variant="ghost" variant="ghost"
> >
<ArrowLeft /> <ArrowLeft />
{subMenuTitle} {subMenuTitle}
</Button> </Button>
<div className="border-t border-border mb-2" /> <div className="mb-2 border-t border-border" />
{activeSubMenu.map((subAction, index) => ( {activeSubMenu.map((subAction, index) => (
<Button <Button
key={index} key={index}
onClick={subAction.onClick} onClick={subAction.onClick}
className={`w-full p-6 justify-start text-lg gap-4 ${subAction.className || ''}`} className={`w-full justify-start gap-4 p-6 text-lg ${subAction.className || ''}`}
variant="ghost" variant="ghost"
> >
{subAction.label} {subAction.label}

View file

@ -25,7 +25,7 @@ export default function RawEventDialog({
<DialogDescription className="hidden" /> <DialogDescription className="hidden" />
</DialogHeader> </DialogHeader>
<ScrollArea className="h-full"> <ScrollArea className="h-full">
<pre className="text-sm text-muted-foreground select-text"> <pre className="select-text text-sm text-muted-foreground">
{JSON.stringify(event, null, 2)} {JSON.stringify(event, null, 2)}
</pre> </pre>
<ScrollBar orientation="horizontal" /> <ScrollBar orientation="horizontal" />

Some files were not shown because too many files have changed in this diff Show more