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
printWidth: 100
trailingComma: none
plugins: [prettier-plugin-tailwindcss]

80
package-lock.json generated
View file

@ -95,6 +95,7 @@
"globals": "^15.13.0",
"postcss": "^8.4.49",
"prettier": "3.4.2",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",
"typescript-eslint": "^8.18.1",
@ -10392,6 +10393,85 @@
"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": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz",

View file

@ -105,6 +105,7 @@
"globals": "^15.13.0",
"postcss": "^8.4.49",
"prettier": "3.4.2",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",
"typescript-eslint": "^8.18.1",

View file

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

View file

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

View file

@ -37,18 +37,18 @@ export default function AccountList({
.finally(() => setSwitchingAccount(null))
}}
>
<div className="flex justify-between items-center p-2">
<div className="flex-1 flex items-center gap-2 relative">
<div className="flex items-center justify-between p-2">
<div className="relative flex flex-1 items-center gap-2">
<SimpleUserAvatar userId={act.pubkey} />
<div className="flex-1 w-0">
<SimpleUsername userId={act.pubkey} className="font-semibold truncate" />
<div className="text-sm rounded-full bg-muted px-2 w-fit">
<div className="w-0 flex-1">
<SimpleUsername userId={act.pubkey} className="truncate font-semibold" />
<div className="w-fit rounded-full bg-muted px-2 text-sm">
{formatPubkey(act.pubkey)}
</div>
</div>
</div>
<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} />
</div>
<Button
@ -65,7 +65,7 @@ export default function AccountList({
</div>
</div>
{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" />
</div>
)}

View file

@ -42,7 +42,7 @@ export default function BunkerLogin({
onChange={handleInputChange}
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>
<Button onClick={handleLogin} disabled={pending}>
<Loader className={pending ? 'animate-spin' : 'hidden'} />

View file

@ -186,17 +186,17 @@ export default function NostrConnectLogin({
return (
<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">
<QrCode size={qrCodeSize} value={loginDetails.connectionString} />
</a>
{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 className="flex justify-center w-full mb-3">
<div className="mb-3 flex w-full justify-center">
<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={{
width: qrCodeSize > 0 ? `${Math.max(150, Math.min(qrCodeSize, 320))}px` : 'auto'
}}
@ -204,14 +204,14 @@ export default function NostrConnectLogin({
role="button"
tabIndex={0}
>
<div className="flex-grow min-w-0 truncate select-none">
<div className="min-w-0 flex-grow select-none truncate">
{loginDetails.connectionString}
</div>
<div className="flex-shrink-0">{copied ? <Check size={14} /> : <Copy size={14} />}</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>
<span className="px-3 text-xs text-muted-foreground">OR</span>
<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="flex items-start space-x-2">
<div className="flex-1 relative">
<div className="relative flex-1">
<Input
placeholder="bunker://..."
value={bunkerInput}
@ -229,7 +229,7 @@ export default function NostrConnectLogin({
<Button
size="sm"
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}
disabled={pending}
>
@ -237,21 +237,21 @@ export default function NostrConnectLogin({
</Button>
</div>
<Button onClick={() => handleLogin()} disabled={pending}>
<Loader className={pending ? 'animate-spin mr-2' : 'hidden'} />
<Loader className={pending ? 'mr-2 animate-spin' : 'hidden'} />
{t('Login')}
</Button>
</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>
<Button variant="secondary" onClick={back} className="w-full">
{t('Back')}
</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
ref={videoRef}
className="absolute inset-0 w-full h-full bg-background"
className="absolute inset-0 h-full w-full bg-background"
autoPlay
playsInline
muted
@ -259,7 +259,7 @@ export default function NostrConnectLogin({
<Button
variant="secondary"
size="sm"
className="absolute top-2 right-2"
className="absolute right-2 top-2"
onClick={stopQrScan}
>
Cancel

View file

@ -42,7 +42,7 @@ export default function NpubLogin({
onChange={handleInputChange}
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>
<Button onClick={handleLogin} disabled={pending}>
<Loader className={pending ? 'animate-spin' : 'hidden'} />

View file

@ -53,7 +53,7 @@ export default function Signup({
{(['generate', 'password'] as Step[]).map((s, index) => (
<div key={s} className="flex items-center">
<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
? 'bg-primary text-primary-foreground'
: step === 'password' && s === 'generate'
@ -63,7 +63,7 @@ export default function Signup({
>
{index + 1}
</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>
@ -75,7 +75,7 @@ export default function Signup({
{renderStepIndicator()}
<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">
{t('Generate your unique private key. This is your digital identity.')}
</p>
@ -110,7 +110,7 @@ export default function Signup({
</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">
<Download />
{t('Download Backup File')}
@ -129,7 +129,7 @@ export default function Signup({
</Button>
</div>
<div className="flex items-center gap-2 ml-2">
<div className="ml-2 flex items-center gap-2">
<Checkbox
id="acknowledge-checkbox"
checked={checkedSaveKey}
@ -159,7 +159,7 @@ export default function Signup({
{renderStepIndicator()}
<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">
{t('Add an extra layer of protection with a password')}
</p>
@ -201,7 +201,7 @@ export default function Signup({
)}
</div>
<div className="w-full flex gap-2">
<div className="flex w-full gap-2">
<Button
variant="secondary"
onClick={() => {

View file

@ -45,10 +45,10 @@ function AccountManagerNav({
return (
<div onClick={(e) => e.stopPropagation()} className="flex flex-col gap-8">
<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')}
</div>
<div className="space-y-2 mt-4">
<div className="mt-4 space-y-2">
{!!window.nostr && (
<Button onClick={() => nip07Login().then(() => close?.())} className="w-full">
{t('Login with Browser Extension')}
@ -69,10 +69,10 @@ function AccountManagerNav({
</div>
<Separator />
<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?")}
</div>
<Button onClick={() => setPage('signup')} className="w-full mt-4">
<Button onClick={() => setPage('signup')} className="mt-4 w-full">
{t('Create New Account')}
</Button>
</div>
@ -80,7 +80,7 @@ function AccountManagerNav({
<>
<Separator />
<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')}
</div>
<AccountList className="mt-4" afterSwitch={() => close?.()} />

View file

@ -129,7 +129,7 @@ export default function AudioPlayer({
<div
ref={containerRef}
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
)}
onClick={(e) => e.stopPropagation()}
@ -137,12 +137,12 @@ export default function AudioPlayer({
<audio ref={audioRef} src={src} preload="metadata" onError={() => setError(false)} />
{/* 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" />}
</Button>
{/* Progress Section */}
<div className="flex-1 relative">
<div className="relative flex-1">
<Slider
value={[currentTime]}
max={duration || 100}
@ -153,14 +153,14 @@ export default function AudioPlayer({
/>
</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))}
</div>
{isMinimized ? (
<Button
variant="ghost"
size="icon"
className="rounded-full shrink-0 text-muted-foreground"
className="shrink-0 rounded-full text-muted-foreground"
onClick={() => mediaManager.stopAudioBackground()}
>
<X />
@ -169,7 +169,7 @@ export default function AudioPlayer({
<Button
variant="ghost"
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)}
>
<Minimize2 />

View file

@ -52,7 +52,7 @@ export default function BookmarkButton({ stuff }: { stuff: Event | string }) {
<button
className={`flex items-center gap-1 ${
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}
disabled={!event || updating}
title={isBookmarked ? t('Remove bookmark') : t('Bookmark')}

View file

@ -62,7 +62,7 @@ export default function BookmarkList() {
if (eventIds.length === 0) {
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')}
</div>
)
@ -79,7 +79,7 @@ export default function BookmarkList() {
<NoteCardLoadingSkeleton />
</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')}
</div>
)}

View file

@ -42,10 +42,10 @@ export default function AccountButton() {
profile ? (
<SimpleUserAvatar
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 />

View file

@ -18,7 +18,7 @@ export default function BottomNavigationBarItem({
return (
<Button
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'
)}
variant="ghost"

View file

@ -17,7 +17,7 @@ export default function NotificationsButton() {
<div className="relative">
<Bell />
{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>
</BottomNavigationBarItem>

View file

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

View file

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

View file

@ -48,7 +48,7 @@ export default function Collapsible({
return (
<div
className={cn('relative text-left overflow-hidden', className)}
className={cn('relative overflow-hidden text-left', className)}
ref={containerRef}
{...props}
style={{
@ -57,8 +57,8 @@ export default function Collapsible({
>
{children}
{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="bg-background rounded-lg">
<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="rounded-lg bg-background">
<Button
className="bg-foreground hover:bg-foreground/80"
onClick={(e) => {

View file

@ -110,7 +110,7 @@ export default function Content({
let imageIndex = 0
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) => {
if (node.type === 'text') {
return node.data

View file

@ -16,7 +16,7 @@ export default function CommunityDefinitionPreview({
return (
<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>
)
}

View file

@ -16,7 +16,7 @@ export default function EmojiPackPreview({
return (
<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>}
</div>
)

View file

@ -16,7 +16,7 @@ export default function FollowPackPreview({
return (
<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>
)
}

View file

@ -16,7 +16,7 @@ export default function GroupMetadataPreview({
return (
<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>
)
}

View file

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

View file

@ -16,7 +16,7 @@ export default function LiveEventPreview({
return (
<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>
)
}

View file

@ -16,7 +16,7 @@ export default function LongFormArticlePreview({
return (
<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>
)
}

View file

@ -13,7 +13,7 @@ export default function PictureNotePreview({
return (
<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>
)
}

View file

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

View file

@ -13,7 +13,7 @@ export default function VideoNotePreview({
return (
<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>
)
}

View file

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

View file

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

View file

@ -21,23 +21,23 @@ export default function RecentSupporters() {
return (
<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">
{supporters.map((item, index) => (
<div
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} />
<div className="flex-1 w-0">
<Username className="font-semibold w-fit" userId={item.pubkey} />
<div className="text-xs text-muted-foreground line-clamp-3 select-text">
<div className="w-0 flex-1">
<Username className="w-fit font-semibold" userId={item.pubkey} />
<div className="line-clamp-3 select-text text-xs text-muted-foreground">
{item.comment}
</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')}
</div>
</div>

View file

@ -13,12 +13,12 @@ export default function Donation({ className }: { className?: string }) {
const [donationAmount, setDonationAmount] = useState<number | undefined>(undefined)
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 text-muted-foreground">
{t('Your donation helps me maintain Jumble and make it better! 😊')}
</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: 10000, text: '🍜 10k' },

View file

@ -15,7 +15,7 @@ export default function DrawerMenuItem({
<DrawerClose className="w-full">
<Button
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"
>
{children}

View file

@ -42,21 +42,21 @@ export function EmbeddedLNInvoice({ invoice, className }: { invoice: string; cla
return (
<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()}
>
<div className="flex items-center gap-2">
<Zap className="w-5 h-5 text-yellow-400" />
<div className="font-semibold text-sm">{t('Lightning Invoice')}</div>
<Zap className="h-5 w-5 text-yellow-400" />
<div className="text-sm font-semibold">{t('Lightning Invoice')}</div>
</div>
{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">
{formatAmount(amount)} {t('sats')}
</div>
<Button onClick={handlePayClick}>
{paying && <Loader className="w-4 h-4 animate-spin" />}
{paying && <Loader className="h-4 w-4 animate-spin" />}
{t('Pay')}
</Button>
</div>

View file

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

View file

@ -29,18 +29,18 @@ export function EmbeddedNote({ noteId, className }: { noteId: string; className?
function EmbeddedNoteSkeleton({ className }: { className?: string }) {
return (
<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()}
>
<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>
<Skeleton className="h-3 w-16 my-1" />
<Skeleton className="h-3 w-16 my-1" />
<Skeleton className="my-1 h-3 w-16" />
<Skeleton className="my-1 h-3 w-16" />
</div>
</div>
<Skeleton className="w-full h-4 my-1 mt-2" />
<Skeleton className="w-2/3 h-4 my-1" />
<Skeleton className="my-1 mt-2 h-4 w-full" />
<Skeleton className="my-1 h-4 w-2/3" />
</div>
)
}
@ -49,10 +49,10 @@ function EmbeddedNoteNotFound({ noteId, className }: { noteId: string; className
const { t } = useTranslation()
return (
<div className={cn('text-left p-2 sm:p-3 border rounded-xl bg-card', className)}>
<div className="flex flex-col items-center text-muted-foreground font-medium gap-2">
<div className={cn('rounded-xl border bg-card p-2 text-left sm:p-3', className)}>
<div className="flex flex-col items-center gap-2 font-medium text-muted-foreground">
<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>
)

View file

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

View file

@ -17,7 +17,7 @@ export default function Emoji({
if (typeof emoji === 'string') {
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>
)
@ -34,7 +34,7 @@ export default function Emoji({
src={emoji.url}
alt={emoji.shortcode}
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={() => {
setHasError(false)
}}

View file

@ -56,7 +56,7 @@ export default function EmojiPackList() {
if (eventIds.length === 0) {
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')}
</div>
)

View file

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

View file

@ -28,9 +28,9 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
render() {
if (this.state.hasError) {
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>
<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{' '}
<a
href="https://github.com/CodyTseng/jumble/issues/new"
@ -61,7 +61,7 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
>
Copy Error Message
</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}
</pre>
</>

View file

@ -30,7 +30,7 @@ export default function Explore() {
<div className="p-4 max-md:border-b">
<Skeleton className="h-6 w-20" />
</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" />
</div>
</div>
@ -62,13 +62,13 @@ function RelayCollection({ collection }: { collection: TAwesomeRelayCollection }
<div>
<div
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'
)}
>
{collection.name}
</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) => (
<RelayItem key={url} url={url} />
))}
@ -82,7 +82,7 @@ function RelayItem({ url }: { url: string }) {
const { relayInfo, isFetching } = useFetchRelayInfo(url)
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) {
@ -92,7 +92,7 @@ function RelayItem({ url }: { url: string }) {
return (
<RelaySimpleInfo
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}
onClick={(e) => {
e.stopPropagation()

View file

@ -40,7 +40,7 @@ export default function ExternalContent({
if (node.type === 'text') {
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 (
<div className="w-fit">
<div className="flex relative">
<div className="relative flex">
{TABS.map((tab, index) => (
<div
key={tab.value}
ref={(el) => (tabRefs.current[index] = el)}
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'
)}
onClick={() => onTabChange(tab.value)}
@ -52,7 +52,7 @@ export function Tabs({
</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={{
width: `${indicatorStyle.width}px`,
left: `${indicatorStyle.left}px`

View file

@ -32,12 +32,12 @@ export default function ExternalContentInteractions({
return (
<>
<div className="flex items-center justify-between">
<ScrollArea className="flex-1 w-0">
<ScrollArea className="w-0 flex-1">
<Tabs selectedTab={type} onTabChange={setType} />
<ScrollBar orientation="horizontal" className="opacity-0 pointer-events-none" />
<ScrollBar orientation="horizontal" className="pointer-events-none opacity-0" />
</ScrollArea>
<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} />
</div>
</div>

View file

@ -92,7 +92,7 @@ export default function ExternalLink({
<div className="py-2">
<Button
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"
>
<ExternalLinkIcon />
@ -100,7 +100,7 @@ export default function ExternalLink({
</Button>
<Button
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"
>
<MessageSquare />

View file

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

View file

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

View file

@ -43,7 +43,7 @@ export default function FavoriteRelayList() {
return (
<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
sensors={sensors}
collisionDetection={closestCenter}

View file

@ -40,7 +40,7 @@ export default function PullRelaySetsButton() {
const trigger = (
<Button
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}
>
<CloudDownload />
@ -53,7 +53,7 @@ export default function PullRelaySetsButton() {
<Drawer open={open} onOpenChange={setOpen}>
<DrawerTrigger asChild>{trigger}</DrawerTrigger>
<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>
<DrawerTitle>{t('Select the relay sets you want to pull')}</DrawerTitle>
<DrawerDescription className="hidden" />

View file

@ -20,22 +20,22 @@ export default function RelayItem({ relay }: { relay: string }) {
return (
<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}
style={style}
onClick={() => push(toRelay(relay))}
>
<div className="flex items-center gap-1 flex-1">
<div className="flex flex-1 items-center gap-1">
<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}
{...listeners}
>
<GripVertical className="size-4 text-muted-foreground" />
</div>
<div className="flex gap-2 items-center flex-1">
<div className="flex flex-1 items-center gap-2">
<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>
<SaveRelayDropdownMenu urls={[relay]} />

View file

@ -42,19 +42,19 @@ export default function RelaySet({ relaySet }: { relaySet: TRelaySet }) {
}
return (
<div ref={setNodeRef} style={style} className="relative group">
<div className="w-full border rounded-lg px-2 py-2.5">
<div className="flex justify-between items-center">
<div ref={setNodeRef} style={style} className="group relative">
<div className="w-full rounded-lg border px-2 py-2.5">
<div className="flex items-center justify-between">
<div className="flex items-center">
<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}
{...listeners}
>
<GripVertical className="size-4 text-muted-foreground" />
</div>
<div className="flex gap-2 items-center">
<div className="flex justify-center items-center w-6 h-6 shrink-0">
<div className="flex items-center gap-2">
<div className="flex h-6 w-6 shrink-0 items-center justify-center">
<FolderClosed className="size-4" />
</div>
<RelaySetName relaySet={relaySet} />
@ -98,20 +98,20 @@ function RelaySetName({ relaySet }: { relaySet: TRelaySet }) {
}
return renamingRelaySetId === relaySet.id ? (
<div className="flex gap-1 items-center">
<div className="flex items-center gap-1">
<Input
value={newSetName}
onChange={handleRenameInputChange}
onBlur={saveNewRelaySetName}
onKeyDown={handleRenameInputKeyDown}
className="font-semibold w-28"
className="w-28 font-semibold"
/>
<Button variant="ghost" size="icon" onClick={saveNewRelaySetName}>
<Check size={18} className="text-green-500" />
</Button>
</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()
return (
<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))}
>
<div className="select-none">{children}</div>

View file

@ -45,7 +45,7 @@ export default function RelaySetList() {
return (
<div className="space-y-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')}
</div>
<PullRelaySetsButton />

View file

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

View file

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

View file

@ -53,7 +53,7 @@ export default function FollowButton({ pubkey }: { pubkey: string }) {
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
className="rounded-full min-w-28"
className="min-w-28 rounded-full"
variant={hover ? 'destructive' : 'secondary'}
disabled={updating}
onMouseEnter={() => setHover(true)}
@ -85,7 +85,7 @@ export default function FollowButton({ pubkey }: { pubkey: string }) {
</AlertDialog>
</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')}
</Button>
)

View file

@ -16,7 +16,7 @@ export default function FollowingBadge({ pubkey, userId }: { pubkey?: string; us
if (!isFollowing) return null
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" />
</div>
)

View file

@ -64,7 +64,7 @@ export default function FollowingFavoriteRelayList() {
{showCount < relays.length && <div ref={bottomRef} />}
{loading && <RelaySimpleInfoSkeleton className="p-4" />}
{!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')}
</div>
)}
@ -81,7 +81,7 @@ function RelayItem({ url, users }: { url: string; users: string[] }) {
key={url}
relayInfo={relayInfo}
users={users}
className="clickable p-4 border-b"
className="clickable border-b p-4"
onClick={(e) => {
e.stopPropagation()
push(toRelay(url))

View file

@ -87,7 +87,7 @@ export default function HighlightButton({ onHighlight, containerRef }: Highlight
return (
<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={{
top: `${position.top}px`,
left: `${position.left}px`
@ -97,7 +97,7 @@ export default function HighlightButton({ onHighlight, containerRef }: Highlight
ref={buttonRef}
size="sm"
variant="default"
className="shadow-lg gap-2 -translate-x-1/2"
className="-translate-x-1/2 gap-2 shadow-lg"
onClick={(e) => {
e.stopPropagation()
onHighlight(selectedText)

View file

@ -79,7 +79,7 @@ export default function Image({
<img
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(
'object-cover transition-opacity pointer-events-none w-full h-full',
'pointer-events-none h-full w-full object-cover transition-opacity',
className
)}
alt=""
@ -91,7 +91,7 @@ export default function Image({
<ThumbHashPlaceholder
thumbHash={thumbHash}
className={cn(
'w-full h-full transition-opacity',
'h-full w-full transition-opacity',
isLoading ? 'opacity-100' : 'opacity-0'
)}
/>
@ -99,14 +99,14 @@ export default function Image({
<BlurHashCanvas
blurHash={blurHash}
className={cn(
'w-full h-full transition-opacity',
'h-full w-full transition-opacity',
isLoading ? 'opacity-100' : 'opacity-0'
)}
/>
) : (
<Skeleton
className={cn(
'w-full h-full transition-opacity',
'h-full w-full transition-opacity',
isLoading ? 'opacity-100' : 'opacity-0',
classNames.skeleton
)}
@ -124,8 +124,8 @@ export default function Image({
onLoad={handleLoad}
onError={handleError}
className={cn(
'object-cover transition-opacity pointer-events-none w-full h-full',
isLoading ? 'opacity-0 absolute inset-0' : '',
'pointer-events-none h-full w-full object-cover transition-opacity',
isLoading ? 'absolute inset-0 opacity-0' : '',
className
)}
/>
@ -137,12 +137,12 @@ export default function Image({
alt={alt}
decoding="async"
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
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,
classNames.errorPlaceholder
)}
@ -188,7 +188,7 @@ function BlurHashCanvas({ blurHash, className = '' }: { blurHash: string; classN
ref={canvasRef}
width={blurHashWidth}
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={{
imageRendering: 'auto',
filter: 'blur(0.5px)'
@ -218,7 +218,7 @@ function ThumbHashPlaceholder({
return (
<div
className={cn('w-full h-full object-cover rounded-lg', className)}
className={cn('h-full w-full rounded-lg object-cover', className)}
style={{
backgroundImage: `url(${dataUrl})`,
backgroundSize: 'cover',

View file

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

View file

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

View file

@ -25,7 +25,7 @@ export default function InfoCard({
variant?: 'info' | 'success' | 'alert'
}) {
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">
{icon ?? ICON_MAP[variant]}
<div className="font-medium">{title}</div>

View file

@ -95,7 +95,7 @@ export default function KindFilter({
>
<ListFilter size={16} />
{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>
)
@ -109,7 +109,7 @@ export default function KindFilter({
<div
key={label}
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'
)}
onClick={() => {
@ -122,14 +122,14 @@ export default function KindFilter({
}
}}
>
<p className="leading-none font-medium">{t(label)}</p>
<p className="text-muted-foreground text-xs">kind {kindGroup.join(', ')}</p>
<p className="font-medium leading-none">{t(label)}</p>
<p className="text-xs text-muted-foreground">kind {kindGroup.join(', ')}</p>
</div>
)
})}
</div>
<div className="grid grid-cols-3 gap-2 mt-4">
<div className="mt-4 grid grid-cols-3 gap-2">
<Button
variant="secondary"
onClick={() => {
@ -155,7 +155,7 @@ export default function KindFilter({
</Button>
</div>
<Label className="flex items-center gap-2 cursor-pointer mt-4">
<Label className="mt-4 flex cursor-pointer items-center gap-2">
<Checkbox
id="persistent-filter"
checked={isPersistent}

View file

@ -4,7 +4,7 @@ export function LoadingBar({ className }: { className?: string }) {
return (
<div className={cn('h-0.5 w-full overflow-hidden', className)}>
<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={{
backgroundSize: '400% 100%'
}}

View file

@ -17,7 +17,7 @@ export default function LoginDialog({
return (
<Drawer open={open} onOpenChange={setOpen}>
<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)} />
</div>
</DrawerContent>
@ -27,7 +27,7 @@ export default function LoginDialog({
return (
<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)} />
</DialogContent>
</Dialog>

View file

@ -38,21 +38,21 @@ export default function MailboxRelay({
return (
<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
{...attributes}
{...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' }}
>
<GripVertical size={16} className="text-muted-foreground" />
</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))}
>
<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 className="flex items-center gap-4">
@ -72,7 +72,7 @@ export default function MailboxRelay({
<CircleX
size={16}
onClick={() => removeMailboxRelay(mailboxRelay.url)}
className="text-muted-foreground hover:text-destructive clickable"
className="clickable text-muted-foreground hover:text-destructive"
/>
</div>
</div>

View file

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

View file

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

View file

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

View file

@ -91,7 +91,7 @@ export default function MuteButton({ pubkey }: { pubkey: string }) {
<DrawerContent>
<div className="py-2">
<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"
onClick={(e) => handleMute(e, true)}
disabled={updating || changing}
@ -99,7 +99,7 @@ export default function MuteButton({ pubkey }: { pubkey: string }) {
{updating ? <Loader className="animate-spin" /> : t('Mute user privately')}
</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"
onClick={(e) => handleMute(e, false)}
disabled={updating || changing}

View file

@ -37,7 +37,7 @@ export default function NewNotesButton({
{newEvents.length > 0 && (
<div
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'
)}
style={{
@ -48,10 +48,10 @@ export default function NewNotesButton({
>
<Button
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 && (
<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) => (
<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()}
>
{nip05Name !== '_' ? (
<span className="text-sm text-muted-foreground truncate">@{nip05Name}</span>
<span className="truncate text-sm text-muted-foreground">@{nip05Name}</span>
) : null}
{nip05IsVerified ? (
<Favicon
domain={nip05Domain}
className="w-3.5 h-3.5 rounded-full shrink-0"
fallback={<BadgeCheck className="text-primary shrink-0" />}
className="h-3.5 w-3.5 shrink-0 rounded-full"
fallback={<BadgeCheck className="shrink-0 text-primary" />}
/>
) : (
<BadgeAlert className="text-muted-foreground shrink-0" />
<BadgeAlert className="shrink-0 text-muted-foreground" />
)}
<SecondaryPageLink
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}
</SecondaryPageLink>
{append && <span className="text-sm text-muted-foreground truncate">{append}</span>}
{append && <span className="truncate text-sm text-muted-foreground">{append}</span>}
</div>
)
}

View file

@ -4,7 +4,7 @@ export default function NotFound() {
const { t } = useTranslation()
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>(404)</div>
</div>

View file

@ -16,11 +16,11 @@ export default function CommunityDefinition({
const metadata = useMemo(() => getCommunityDefinitionFromEvent(event), [event])
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 && (
<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 (
@ -29,16 +29,16 @@ export default function CommunityDefinition({
{metadata.image && autoLoadMedia && (
<Image
image={{ url: metadata.image, pubkey: event.pubkey }}
className="aspect-square bg-foreground h-20"
className="aspect-square h-20 bg-foreground"
hideIfError
/>
)}
<div className="flex-1 w-0 space-y-1">
<div className="w-0 flex-1 space-y-1">
{communityNameComponent}
{communityDescriptionComponent}
</div>
</div>
<ClientSelect className="w-full mt-2" event={event} />
<ClientSelect className="mt-2 w-full" event={event} />
</div>
)
}

View file

@ -44,7 +44,7 @@ export default function EmojiPack({ event, className }: { event: Event; classNam
return (
<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>
{accountPubkey && (
<Button
@ -55,7 +55,7 @@ export default function EmojiPack({ event, className }: { event: Event; classNam
className="shrink-0"
>
{updating ? (
<Loader className="animate-spin mr-1" />
<Loader className="mr-1 animate-spin" />
) : isCollected ? (
<CheckIcon />
) : (

View file

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

View file

@ -18,11 +18,11 @@ export default function GroupMetadata({
const metadata = useMemo(() => getGroupMetadataFromEvent(event), [event])
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 && (
<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 (
@ -31,16 +31,16 @@ export default function GroupMetadata({
{metadata.picture && autoLoadMedia && (
<Image
image={{ url: metadata.picture, pubkey: event.pubkey }}
className="aspect-square bg-foreground h-20"
className="aspect-square h-20 bg-foreground"
hideIfError
/>
)}
<div className="flex-1 w-0 space-y-1">
<div className="w-0 flex-1 space-y-1">
{groupNameComponent}
{groupAboutComponent}
</div>
</div>
<ClientSelect className="w-full mt-2" event={event} originalNoteId={originalNoteId} />
<ClientSelect className="mt-2 w-full" event={event} originalNoteId={originalNoteId} />
</div>
)
}

View file

@ -21,12 +21,12 @@ export default function Highlight({ event, className }: { event: Event; classNam
)
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 })} />}
<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
className="italic whitespace-pre-line"
className="whitespace-pre-line italic"
style={{
overflowWrap: 'anywhere'
}}
@ -112,7 +112,7 @@ function HighlightSource({ event }: { event: Event }) {
{t('From')}{' '}
<ExternalLink
url={sourceTag[1]}
className="underline italic text-muted-foreground hover:text-foreground"
className="italic text-muted-foreground underline hover:text-foreground"
/>
</div>
)
@ -124,7 +124,7 @@ function HighlightSource({ event }: { event: Event }) {
{pubkey && <UserAvatar userId={pubkey} size="xSmall" className="cursor-pointer" />}
{referenceEventId && (
<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) => {
e.stopPropagation()
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>
))
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 && (
<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 && (
<div className="flex gap-1 flex-wrap">
<div className="flex flex-wrap gap-1">
{metadata.tags.map((tag) => (
<Badge key={tag} variant="secondary">
{tag}
@ -45,7 +45,7 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
{metadata.image && autoLoadMedia && (
<Image
image={{ url: metadata.image, pubkey: event.pubkey }}
className="w-full aspect-video"
className="aspect-video w-full"
hideIfError
/>
)}
@ -54,7 +54,7 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
{liveStatusComponent}
{summaryComponent}
{tagsComponent}
<ClientSelect className="w-full mt-2" event={event} />
<ClientSelect className="mt-2 w-full" event={event} />
</div>
</div>
)
@ -66,18 +66,18 @@ export default function LiveEvent({ event, className }: { event: Event; classNam
{metadata.image && autoLoadMedia && (
<Image
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
/>
)}
<div className="flex-1 w-0 space-y-1">
<div className="w-0 flex-1 space-y-1">
{titleComponent}
{liveStatusComponent}
{summaryComponent}
{tagsComponent}
</div>
</div>
<ClientSelect className="w-full mt-2" event={event} />
<ClientSelect className="mt-2 w-full" event={event} />
</div>
)
}

View file

@ -43,7 +43,7 @@ export default function LongFormArticle({
return (
<SecondaryPageLink
to={toNote(href)}
className="break-words underline text-foreground"
className="break-words text-foreground underline"
>
{children}
</SecondaryPageLink>
@ -53,7 +53,7 @@ export default function LongFormArticle({
return (
<SecondaryPageLink
to={toProfile(href)}
className="break-words underline text-foreground"
className="break-words text-foreground underline"
>
{children}
</SecondaryPageLink>
@ -65,7 +65,7 @@ export default function LongFormArticle({
href={href}
target="_blank"
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" />
</a>
@ -73,11 +73,11 @@ export default function LongFormArticle({
},
p: (props) => <p {...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) => (
<ImageWithLightbox
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={{
wrapper: 'w-fit max-w-full'
}}
@ -91,7 +91,7 @@ export default function LongFormArticle({
<>
<div
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>
{metadata.summary && (
@ -102,7 +102,7 @@ export default function LongFormArticle({
{metadata.image && (
<ImageWithLightbox
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
@ -118,12 +118,12 @@ export default function LongFormArticle({
{event.content}
</Markdown>
{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) => (
<div
key={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) => {
e.stopPropagation()
push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] }))

View file

@ -19,14 +19,14 @@ export default function LongFormArticlePreview({
const { autoLoadMedia } = useContentPolicy()
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 && (
<div className="flex gap-1 flex-wrap">
<div className="flex flex-wrap gap-1">
{metadata.tags.map((tag) => (
<div
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) => {
e.stopPropagation()
push(toNoteList({ hashtag: tag, kinds: [kinds.LongFormArticle] }))
@ -39,7 +39,7 @@ export default function LongFormArticlePreview({
)
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) {
@ -48,7 +48,7 @@ export default function LongFormArticlePreview({
{metadata.image && autoLoadMedia && (
<Image
image={{ url: metadata.image, pubkey: event.pubkey }}
className="w-full aspect-video"
className="aspect-video w-full"
hideIfError
/>
)}
@ -67,11 +67,11 @@ export default function LongFormArticlePreview({
{metadata.image && autoLoadMedia && (
<Image
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
/>
)}
<div className="flex-1 w-0 space-y-1">
<div className="w-0 flex-1 space-y-1">
{titleComponent}
{summaryComponent}
{tagsComponent}

View file

@ -6,7 +6,7 @@ export default function MutedNote({ show }: { show: () => void }) {
const { t } = useTranslation()
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>
<Button
onClick={(e) => {

View file

@ -6,7 +6,7 @@ export default function NsfwNote({ show }: { show: () => void }) {
const { t } = useTranslation()
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>
<Button
onClick={(e) => {

View file

@ -170,7 +170,7 @@ export default function Poll({ event, className }: { event: Event; className?: s
key={option.id}
title={option.label}
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 &&
(selectedOptionIds.includes(option.id)
@ -184,7 +184,7 @@ export default function Poll({ event, className }: { event: Event; className?: s
disabled={!canVote}
>
{/* 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' : '')}>
{option.label}
</div>
@ -195,7 +195,7 @@ export default function Poll({ event, className }: { event: Event; className?: s
{showResults && (
<div
className={cn(
'text-muted-foreground shrink-0 z-10',
'z-10 shrink-0 text-muted-foreground',
isMax ? 'font-semibold text-foreground' : ''
)}
>
@ -217,13 +217,13 @@ export default function Poll({ event, className }: { event: Event; className?: s
</div>
{/* 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>
{isLoadingResults && t('Loading...')}
{!isLoadingResults && showResults && (
<div
className="hover:underline cursor-pointer"
className="cursor-pointer hover:underline"
onClick={(e) => {
e.stopPropagation()
fetchResults()

View file

@ -20,7 +20,7 @@ export default function RelayReview({ event, className }: { event: Event; classN
<Stars stars={stars} />
<span className="text-sm text-muted-foreground"></span>
<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) => {
e.stopPropagation()
push(toRelay(url))

View file

@ -9,7 +9,7 @@ export default function UnknownNote({ event, className }: { event: Event; classN
return (
<div
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
)}
>

View file

@ -122,14 +122,14 @@ export default function Note({
return (
<div className={className}>
<div className="flex justify-between items-start gap-2">
<div className="flex items-center space-x-2 flex-1">
<div className="flex items-start justify-between gap-2">
<div className="flex flex-1 items-center space-x-2">
<UserAvatar userId={event.pubkey} size={size === 'small' ? 'medium' : 'normal'} />
<div className="flex-1 w-0">
<div className="flex gap-2 items-center">
<div className="w-0 flex-1">
<div className="flex items-center gap-2">
<Username
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'}
/>
<FollowingBadge pubkey={event.pubkey} />
@ -149,7 +149,7 @@ export default function Note({
<div className="flex items-center">
<TranslateButton event={event} className={size === 'normal' ? '' : 'pr-0'} />
{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>

View file

@ -37,7 +37,7 @@ export default function MainNoteCard({
<div
className={cn(
'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}>

View file

@ -15,7 +15,7 @@ export default function PinnedButton({ event }: { event: NostrEvent }) {
if (event.pubkey !== pubkey) {
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" />
{t('Pinned')}
</div>
@ -24,7 +24,7 @@ export default function PinnedButton({ event }: { event: NostrEvent }) {
return (
<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"
onClick={(e) => {
e.stopPropagation()
@ -36,7 +36,7 @@ export default function PinnedButton({ event }: { event: NostrEvent }) {
onMouseLeave={() => setHovered(false)}
>
{unpinning ? (
<Loader size={16} className="animate-spin shrink-0" />
<Loader size={16} className="shrink-0 animate-spin" />
) : (
<Pin size={16} className="shrink-0" />
)}

View file

@ -22,19 +22,19 @@ export default function RepostDescription({
if (!reposters?.length) return null
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" />
<Username
key={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"
/>
{reposters.length > 1 && (
<Username
key={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"
/>
)}
@ -44,7 +44,7 @@ export default function RepostDescription({
<Username
key={reposters[2]}
userId={reposters[2]}
className={cn('font-semibold truncate')}
className={cn('truncate font-semibold')}
skeletonClassName="h-3"
/>
) : null}
@ -63,7 +63,7 @@ function AndXOthers({ reposters }: { reposters: string[] }) {
{t('and {{x}} others', { x: reposters.length })}
</span>
</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) => (
<div key={pubkey} className="p-2">
<UserAvatar key={pubkey} userId={pubkey} size="small" />

View file

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

View file

@ -39,13 +39,13 @@ export function Tabs({
return (
<div className="w-fit">
<div className="flex relative">
<div className="relative flex">
{TABS.map((tab, index) => (
<div
key={tab.value}
ref={(el) => (tabRefs.current[index] = el)}
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'
)}
onClick={() => onTabChange(tab.value)}
@ -54,7 +54,7 @@ export function Tabs({
</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={{
width: `${indicatorStyle.width}px`,
left: `${indicatorStyle.left}px`

View file

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

View file

@ -492,12 +492,12 @@ const NoteList = forwardRef<
{shouldShowLoadingIndicator || filtering || initialLoading ? (
<NoteCardLoadingSkeleton />
) : 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-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>
<Button size="lg" onClick={() => setRefreshCount((count) => count + 1)}>
{t('Reload')}

View file

@ -40,7 +40,7 @@ export function MobileMenu({
<Button
key={index}
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"
>
<Icon />
@ -52,18 +52,18 @@ export function MobileMenu({
<>
<Button
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"
>
<ArrowLeft />
{subMenuTitle}
</Button>
<div className="border-t border-border mb-2" />
<div className="mb-2 border-t border-border" />
{activeSubMenu.map((subAction, index) => (
<Button
key={index}
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"
>
{subAction.label}

View file

@ -25,7 +25,7 @@ export default function RawEventDialog({
<DialogDescription className="hidden" />
</DialogHeader>
<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)}
</pre>
<ScrollBar orientation="horizontal" />

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