improve UX of notifications

This commit is contained in:
keyan 2024-07-11 16:59:07 -05:00
parent 28c4fa160c
commit 07042c57ca
4 changed files with 108 additions and 73 deletions

View File

@ -43,7 +43,7 @@ function Notification ({ n, fresh }) {
const type = n.__typename const type = n.__typename
return ( return (
<NotificationLayout nid={nid(n)} {...defaultOnClick(n)} fresh={fresh}> <NotificationLayout nid={nid(n)} type={type} {...defaultOnClick(n)} fresh={fresh}>
{ {
(type === 'Earn' && <EarnNotification n={n} />) || (type === 'Earn' && <EarnNotification n={n} />) ||
(type === 'Revenue' && <RevenueNotification n={n} />) || (type === 'Revenue' && <RevenueNotification n={n} />) ||
@ -70,12 +70,12 @@ function Notification ({ n, fresh }) {
) )
} }
function NotificationLayout ({ children, nid, href, as, fresh }) { function NotificationLayout ({ children, type, nid, href, as, fresh }) {
const router = useRouter() const router = useRouter()
if (!href) return <div className={fresh ? styles.fresh : ''}>{children}</div> if (!href) return <div className={`py-2 ${fresh ? styles.fresh : ''}`}>{children}</div>
return ( return (
<LinkToContext <LinkToContext
className={`${fresh ? styles.fresh : ''} ${router?.query?.nid === nid ? 'outline-it' : ''}`} className={`py-2 ${type === 'Reply' ? styles.reply : ''} ${fresh ? styles.fresh : ''} ${router?.query?.nid === nid ? 'outline-it' : ''}`}
onClick={async (e) => { onClick={async (e) => {
e.preventDefault() e.preventDefault()
nid && await router.replace({ nid && await router.replace({
@ -94,6 +94,14 @@ function NotificationLayout ({ children, nid, href, as, fresh }) {
) )
} }
function NoteHeader ({ color, children, big }) {
return (
<div className={`fw-bold text-${color} ${big ? '' : 'small'} d-inline-flex align-items-center pb-2`} style={{ lineHeight: '1.25' }}>
{children}
</div>
)
}
const defaultOnClick = n => { const defaultOnClick = n => {
const type = n.__typename const type = n.__typename
if (type === 'Earn') { if (type === 'Earn') {
@ -159,7 +167,7 @@ function Streak ({ n }) {
} }
return ( return (
<div className='d-flex ms-2 py-1'> <div className='d-flex'>
<div style={{ fontSize: '2rem' }}>{n.days ? <BaldIcon className='fill-grey' height={40} width={40} /> : <CowboyHatIcon className='fill-grey' height={40} width={40} />}</div> <div style={{ fontSize: '2rem' }}>{n.days ? <BaldIcon className='fill-grey' height={40} width={40} /> : <CowboyHatIcon className='fill-grey' height={40} width={40} />}</div>
<div className='ms-1 p-1'> <div className='ms-1 p-1'>
<span className='fw-bold'>you {n.days ? 'lost your' : 'found a'} cowboy hat</span> <span className='fw-bold'>you {n.days ? 'lost your' : 'found a'} cowboy hat</span>
@ -173,12 +181,12 @@ function EarnNotification ({ n }) {
const time = n.minSortTime === n.sortTime ? dayMonthYear(new Date(n.minSortTime)) : `${dayMonthYear(new Date(n.minSortTime))} to ${dayMonthYear(new Date(n.sortTime))}` const time = n.minSortTime === n.sortTime ? dayMonthYear(new Date(n.minSortTime)) : `${dayMonthYear(new Date(n.minSortTime))} to ${dayMonthYear(new Date(n.sortTime))}`
return ( return (
<div className='d-flex ms-2 py-1'> <div className='d-flex'>
<HandCoin className='align-self-center fill-boost mx-1' width={24} height={24} style={{ flex: '0 0 24px', transform: 'rotateY(180deg)' }} /> <HandCoin className='align-self-center fill-boost mx-1' width={24} height={24} style={{ flex: '0 0 24px', transform: 'rotateY(180deg)' }} />
<div className='mx-2'> <div className='ms-2'>
<div className='fw-bold text-boost'> <NoteHeader color='boost' big>
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in rewards<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{time}</small> you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in rewards<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{time}</small>
</div> </NoteHeader>
{n.sources && {n.sources &&
<div style={{ fontSize: '80%', color: 'var(--theme-grey)' }}> <div style={{ fontSize: '80%', color: 'var(--theme-grey)' }}>
{n.sources.posts > 0 && <span>{numWithUnits(n.sources.posts, { abbreviate: false })} for top posts</span>} {n.sources.posts > 0 && <span>{numWithUnits(n.sources.posts, { abbreviate: false })} for top posts</span>}
@ -197,12 +205,12 @@ function EarnNotification ({ n }) {
function ReferralReward ({ n }) { function ReferralReward ({ n }) {
return ( return (
<div className='d-flex ms-2 py-1'> <div className='d-flex'>
<UserAdd className='align-self-center fill-success mx-1' width={24} height={24} style={{ flex: '0 0 24px', transform: 'rotateY(180deg)' }} /> <UserAdd className='align-self-center fill-success mx-1' width={24} height={24} style={{ flex: '0 0 24px', transform: 'rotateY(180deg)' }} />
<div className='mx-2'> <div className='ms-2'>
<div className='fw-bold text-success'> <NoteHeader color='success' big>
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in referral rewards<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{dayMonthYear(new Date(n.sortTime))}</small> you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in referral rewards<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{dayMonthYear(new Date(n.sortTime))}</small>
</div> </NoteHeader>
{n.sources && {n.sources &&
<div style={{ fontSize: '80%', color: 'var(--theme-grey)' }}> <div style={{ fontSize: '80%', color: 'var(--theme-grey)' }}>
{n.sources.forever > 0 && <span>{numWithUnits(n.sources.forever, { abbreviate: false })} for stackers joining because of you</span>} {n.sources.forever > 0 && <span>{numWithUnits(n.sources.forever, { abbreviate: false })} for stackers joining because of you</span>}
@ -219,9 +227,9 @@ function ReferralReward ({ n }) {
function RevenueNotification ({ n }) { function RevenueNotification ({ n }) {
return ( return (
<div className='d-flex ms-2 py-1'> <div className='d-flex'>
<BountyIcon className='align-self-center fill-success mx-1' width={24} height={24} style={{ flex: '0 0 24px' }} /> <BountyIcon className='align-self-center fill-success mx-1' width={24} height={24} style={{ flex: '0 0 24px' }} />
<div className='ms-2 pb-1'> <div className=' pb-1'>
<div className='fw-bold text-success'> <div className='fw-bold text-success'>
you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in territory revenue<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small> you stacked {numWithUnits(n.earnedSats, { abbreviate: false })} in territory revenue<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
</div> </div>
@ -236,7 +244,7 @@ function RevenueNotification ({ n }) {
function SubStatus ({ n }) { function SubStatus ({ n }) {
const dueDate = nextBillingWithGrace(n.sub) const dueDate = nextBillingWithGrace(n.sub)
return ( return (
<div className={`fw-bold text-${n.sub.status === 'ACTIVE' ? 'success' : 'danger'} ms-2`}> <div className={`fw-bold text-${n.sub.status === 'ACTIVE' ? 'success' : 'danger'} `}>
{n.sub.status === 'ACTIVE' {n.sub.status === 'ACTIVE'
? 'your territory is active again' ? 'your territory is active again'
: (n.sub.status === 'GRACE' : (n.sub.status === 'GRACE'
@ -250,14 +258,14 @@ function SubStatus ({ n }) {
function Invitification ({ n }) { function Invitification ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-secondary ms-2'> <NoteHeader color='secondary'>
your invite has been redeemed by your invite has been redeemed by
{numWithUnits(n.invite.invitees.length, { {numWithUnits(n.invite.invitees.length, {
abbreviate: false, abbreviate: false,
unitSingular: 'stacker', unitSingular: 'stacker',
unitPlural: 'stackers' unitPlural: 'stackers'
})} })}
</small> </NoteHeader>
<div className='ms-4 me-2 mt-1'> <div className='ms-4 me-2 mt-1'>
<Invite <Invite
invite={n.invite} active={ invite={n.invite} active={
@ -275,25 +283,23 @@ function NostrZap ({ n }) {
const { npub, content, note } = nostrZapDetails(nostr) const { npub, content, note } = nostrZapDetails(nostr)
return ( return (
<> <div className='fw-bold text-nostr'>
<div className='fw-bold text-nostr ms-2 py-1'> <NostrIcon width={24} height={24} className='fill-nostr me-1' />{numWithUnits(n.earnedSats)} zap from
<NostrIcon width={24} height={24} className='fill-nostr me-1' />{numWithUnits(n.earnedSats)} zap from {// eslint-disable-next-line
{// eslint-disable-next-line
<Link className='mx-1 text-reset text-underline' target='_blank' href={`https://njump.me/${npub}`} rel={UNKNOWN_LINK_REL}> <Link className='mx-1 text-reset text-underline' target='_blank' href={`https://njump.me/${npub}`} rel={UNKNOWN_LINK_REL}>
{npub.slice(0, 10)}... {npub.slice(0, 10)}...
</Link> </Link>
} }
on {note on {note
? ( ? (
// eslint-disable-next-line // eslint-disable-next-line
<Link className='mx-1 text-reset text-underline' target='_blank' href={`https://njump.me/${note}`} rel={UNKNOWN_LINK_REL}> <Link className='mx-1 text-reset text-underline' target='_blank' href={`https://njump.me/${note}`} rel={UNKNOWN_LINK_REL}>
{note.slice(0, 12)}... {note.slice(0, 12)}...
</Link>) </Link>)
: 'nostr'} : 'nostr'}
<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small> <small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
{content && <small className='d-block ms-4 ps-1 mt-1 mb-1 text-muted fw-normal'><Text>{content}</Text></small>} {content && <small className='d-block ms-4 ps-1 mt-1 mb-1 text-muted fw-normal'><Text>{content}</Text></small>}
</div> </div>
</>
) )
} }
@ -311,7 +317,7 @@ function InvoicePaid ({ n }) {
if (id) payerSig += id if (id) payerSig += id
} }
return ( return (
<div className='fw-bold text-info ms-2 py-1'> <div className='fw-bold text-info'>
<Check className='fill-info me-1' />{numWithUnits(n.earnedSats, { abbreviate: false, unitSingular: 'sat was', unitPlural: 'sats were' })} deposited in your account <Check className='fill-info me-1' />{numWithUnits(n.earnedSats, { abbreviate: false, unitSingular: 'sat was', unitPlural: 'sats were' })} deposited in your account
<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small> <small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
{n.invoice.comment && {n.invoice.comment &&
@ -394,23 +400,23 @@ function Invoicification ({ n: { invoice, sortTime } }) {
({ id: invoiceId, actionState: invoiceActionState } = invoice.itemAct.invoice) ({ id: invoiceId, actionState: invoiceActionState } = invoice.itemAct.invoice)
} }
let colorClass = 'text-info' let colorClass = 'info'
switch (invoiceActionState) { switch (invoiceActionState) {
case 'FAILED': case 'FAILED':
actionString += 'failed' actionString += 'failed'
colorClass = 'text-warning' colorClass = 'warning'
break break
case 'PAID': case 'PAID':
actionString += 'paid' actionString += 'paid'
colorClass = 'text-success' colorClass = 'success'
break break
default: default:
actionString += 'pending' actionString += 'pending'
} }
return ( return (
<div className='px-2'> <div>
<small className={`fw-bold ${colorClass} d-inline-flex align-items-center my-1`}> <NoteHeader color={colorClass}>
{actionString} {actionString}
<span className='ms-1 text-muted fw-light'> {numWithUnits(invoice.satsRequested)}</span> <span className='ms-1 text-muted fw-light'> {numWithUnits(invoice.satsRequested)}</span>
<span className={invoiceActionState === 'FAILED' ? 'visible' : 'invisible'}> <span className={invoiceActionState === 'FAILED' ? 'visible' : 'invisible'}>
@ -430,12 +436,12 @@ function Invoicification ({ n: { invoice, sortTime } }) {
</Button> </Button>
<span className='text-muted ms-2 fw-normal' suppressHydrationWarning>{timeSince(new Date(sortTime))}</span> <span className='text-muted ms-2 fw-normal' suppressHydrationWarning>{timeSince(new Date(sortTime))}</span>
</span> </span>
</small> </NoteHeader>
<div> <div>
{invoice.item.title {invoice.item.title
? <Item item={invoice.item} /> ? <Item item={invoice.item} itemClassName='pt-0' />
: ( : (
<div className='pb-2'> <div>
<RootProvider root={invoice.item.root}> <RootProvider root={invoice.item.root}>
<Comment item={invoice.item} noReply includeParent clickToContext /> <Comment item={invoice.item} noReply includeParent clickToContext />
</RootProvider> </RootProvider>
@ -448,7 +454,7 @@ function Invoicification ({ n: { invoice, sortTime } }) {
function WithdrawlPaid ({ n }) { function WithdrawlPaid ({ n }) {
return ( return (
<div className='fw-bold text-info ms-2 py-1'> <div className='fw-bold text-info'>
<Check className='fill-info me-1' />{numWithUnits(n.earnedSats, { abbreviate: false, unitSingular: 'sat was', unitPlural: 'sats were' })} withdrawn from your account <Check className='fill-info me-1' />{numWithUnits(n.earnedSats, { abbreviate: false, unitSingular: 'sat was', unitPlural: 'sats were' })} withdrawn from your account
<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small> <small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
{n.withdrawl.autoWithdraw && <Badge className={styles.badge} bg={null}>autowithdraw</Badge>} {n.withdrawl.autoWithdraw && <Badge className={styles.badge} bg={null}>autowithdraw</Badge>}
@ -458,7 +464,7 @@ function WithdrawlPaid ({ n }) {
function Referral ({ n }) { function Referral ({ n }) {
return ( return (
<small className='fw-bold text-success ms-2'> <small className='fw-bold text-success'>
<UserAdd className='fill-success me-2' height={21} width={21} style={{ transform: 'rotateY(180deg)' }} />someone joined SN because of you <UserAdd className='fill-success me-2' height={21} width={21} style={{ transform: 'rotateY(180deg)' }} />someone joined SN because of you
<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small> <small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
</small> </small>
@ -480,19 +486,19 @@ function Votification ({ n }) {
} }
return ( return (
<> <>
<small className='fw-bold text-success d-inline-block ms-2 my-1' style={{ lineHeight: '1.25' }}> <NoteHeader color='success'>
your {n.item.title ? 'post' : 'reply'} stacked {numWithUnits(n.earnedSats, { abbreviate: false })} your {n.item.title ? 'post' : 'reply'} stacked {numWithUnits(n.earnedSats, { abbreviate: false })}
{n.item.forwards?.length > 0 && {n.item.forwards?.length > 0 &&
<> <>
{' '}and forwarded {numWithUnits(forwardedSats, { abbreviate: false })} to{' '} {' '}and forwarded {numWithUnits(forwardedSats, { abbreviate: false })} to{' '}
<ForwardedUsers /> <ForwardedUsers />
</>} </>}
</small> </NoteHeader>
<div> <div>
{n.item.title {n.item.title
? <Item item={n.item} /> ? <Item item={n.item} itemClassName='pt-0' />
: ( : (
<div className='pb-2'> <div>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent clickToContext /> <Comment item={n.item} noReply includeParent clickToContext />
</RootProvider> </RootProvider>
@ -506,14 +512,14 @@ function Votification ({ n }) {
function ForwardedVotification ({ n }) { function ForwardedVotification ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-success d-inline-block ms-2 my-1' style={{ lineHeight: '1.25' }}> <NoteHeader color='success'>
you were forwarded {numWithUnits(n.earnedSats, { abbreviate: false })} from you were forwarded {numWithUnits(n.earnedSats, { abbreviate: false })} from
</small> </NoteHeader>
<div> <div>
{n.item.title {n.item.title
? <Item item={n.item} /> ? <Item item={n.item} itemClassName='pt-0' />
: ( : (
<div className='pb-2'> <div>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent clickToContext /> <Comment item={n.item} noReply includeParent clickToContext />
</RootProvider> </RootProvider>
@ -527,14 +533,14 @@ function ForwardedVotification ({ n }) {
function Mention ({ n }) { function Mention ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-info ms-2'> <NoteHeader color='info'>
you were mentioned in you were mentioned in
</small> </NoteHeader>
<div> <div>
{n.item.title {n.item.title
? <Item item={n.item} /> ? <Item item={n.item} itemClassName='pt-0' />
: ( : (
<div className='pb-2'> <div>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent rootText={n.__typename === 'Reply' ? 'replying on:' : undefined} clickToContext /> <Comment item={n.item} noReply includeParent rootText={n.__typename === 'Reply' ? 'replying on:' : undefined} clickToContext />
</RootProvider> </RootProvider>
@ -547,13 +553,13 @@ function Mention ({ n }) {
function ItemMention ({ n }) { function ItemMention ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-info ms-2'> <NoteHeader color='info'>
your item was mentioned in your item was mentioned in
</small> </NoteHeader>
{n.item?.title {n.item?.title
? <div className='ps-2'><Item item={n.item} /></div> ? <div className=''><Item item={n.item} itemClassName='pt-0' /></div>
: ( : (
<div className='pb-2'> <div>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent rootText='replying on:' clickToContext /> <Comment item={n.item} noReply includeParent rootText='replying on:' clickToContext />
</RootProvider> </RootProvider>
@ -565,13 +571,13 @@ function ItemMention ({ n }) {
function JobChanged ({ n }) { function JobChanged ({ n }) {
return ( return (
<> <>
<small className={`fw-bold text-${n.item.status === 'ACTIVE' ? 'success' : 'boost'} ms-1`}> <NoteHeader color={n.item.status === 'ACTIVE' ? 'success' : 'boost'}>
{n.item.status === 'ACTIVE' {n.item.status === 'ACTIVE'
? 'your job is active again' ? 'your job is active again'
: (n.item.status === 'NOSATS' : (n.item.status === 'NOSATS'
? 'your job promotion ran out of sats' ? 'your job promotion ran out of sats'
: 'your job has been stopped')} : 'your job has been stopped')}
</small> </NoteHeader>
<ItemJob item={n.item} /> <ItemJob item={n.item} />
</> </>
) )
@ -579,11 +585,11 @@ function JobChanged ({ n }) {
function Reply ({ n }) { function Reply ({ n }) {
return ( return (
<div className='py-2'> <div className='outline'>
{n.item.title {n.item.title
? <Item item={n.item} /> ? <Item item={n.item} itemClassName='pt-0 pb-2' />
: ( : (
<div className='pb-2'> <div className=''>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent clickToContext rootText='replying on:' /> <Comment item={n.item} noReply includeParent clickToContext rootText='replying on:' />
</RootProvider> </RootProvider>
@ -596,13 +602,13 @@ function Reply ({ n }) {
function FollowActivity ({ n }) { function FollowActivity ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-info ms-2'> <NoteHeader color='info'>
a stacker you subscribe to {n.item.parentId ? 'commented' : 'posted'} a stacker you subscribe to {n.item.parentId ? 'commented' : 'posted'}
</small> </NoteHeader>
{n.item.title {n.item.title
? <div className='ms-2'><Item item={n.item} /></div> ? <div className=''><Item item={n.item} itemClassName='pt-0' /></div>
: ( : (
<div className='pb-2'> <div>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent clickToContext rootText='replying on:' /> <Comment item={n.item} noReply includeParent clickToContext rootText='replying on:' />
</RootProvider> </RootProvider>
@ -615,11 +621,11 @@ function FollowActivity ({ n }) {
function TerritoryPost ({ n }) { function TerritoryPost ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-info ms-2'> <NoteHeader color='info'>
new post in ~{n.item.sub.name} new post in ~{n.item.sub.name}
</small> </NoteHeader>
<div className='ps-2'> <div className=''>
<Item item={n.item} /> <Item item={n.item} itemClassName='pt-0' />
</div> </div>
</> </>
) )
@ -628,7 +634,7 @@ function TerritoryPost ({ n }) {
function TerritoryTransfer ({ n }) { function TerritoryTransfer ({ n }) {
return ( return (
<> <>
<div className='fw-bold text-info ms-2'> <div className='fw-bold text-info '>
~{n.sub.name} was transferred to you ~{n.sub.name} was transferred to you
<small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small> <small className='text-muted ms-1 fw-normal' suppressHydrationWarning>{timeSince(new Date(n.sortTime))}</small>
</div> </div>
@ -639,11 +645,13 @@ function TerritoryTransfer ({ n }) {
function Reminder ({ n }) { function Reminder ({ n }) {
return ( return (
<> <>
<small className='fw-bold text-info ms-2'>you asked to be reminded of this {n.item.title ? 'post' : 'comment'}</small> <NoteHeader color='info'>
you asked to be reminded of this {n.item.title ? 'post' : 'comment'}
</NoteHeader>
{n.item.title {n.item.title
? <div className='ms-2'><Item item={n.item} /></div> ? <div className=''><Item item={n.item} itemClassName='pt-0' /></div>
: ( : (
<div className='pb-2'> <div>
<RootProvider root={n.item.root}> <RootProvider root={n.item.root}>
<Comment item={n.item} noReply includeParent clickToContext rootText='replying on:' /> <Comment item={n.item} noReply includeParent clickToContext rootText='replying on:' />
</RootProvider> </RootProvider>

View File

@ -1,16 +1,41 @@
.fresh { .fresh {
background-color: rgba(128, 128, 128, 0.1);
border-radius: 0; border-radius: 0;
border: solid 1px rgba(0, 123, 190, 0.25);
border-bottom: 0;
border-top: 0;
} }
.fresh:not(.fresh ~ .fresh) { .fresh:not(.fresh ~ .fresh) {
border-top-left-radius: .4rem; border-top-left-radius: .4rem;
border-top-right-radius: .4rem; border-top-right-radius: .4rem;
border-top: solid 1px rgba(0, 123, 190, 0.25);
} }
.fresh:has(+ :not(.fresh)) { .fresh:has(+ :not(.fresh)) {
border-bottom-left-radius: .4rem; border-bottom-left-radius: .4rem;
border-bottom-right-radius: .4rem; border-bottom-right-radius: .4rem;
border-bottom: solid 1px rgba(0, 123, 190, 0.25);
}
.reply {
border-radius: 0;
background-color: var(--theme-note-reply);
border-bottom: 0;
border-top: 0;
}
.reply:hover {
background-color: var(--theme-clickToContextColor);
}
.reply:not(.fresh):not(.reply + .reply) {
border-top-left-radius: .4rem;
border-top-right-radius: .4rem;
}
.reply:not(.fresh):has(+ :not(.reply)) {
border-bottom-left-radius: .4rem;
border-bottom-right-radius: .4rem;
} }
.alertBtn { .alertBtn {

View File

@ -25,7 +25,7 @@ export default function Related ({ ssrData }) {
return ( return (
<Layout> <Layout>
<Item item={item} /> <Item item={item} />
<div className='fw-bold my-2'>related</div> <div className='fw-bold mt-2'>related</div>
<Items <Items
ssrData={ssrData} ssrData={ssrData}
query={RELATED_ITEMS} query={RELATED_ITEMS}

View File

@ -151,6 +151,7 @@ $zindex-sticky: 900;
--theme-quoteBar: rgb(206, 208, 212); --theme-quoteBar: rgb(206, 208, 212);
--theme-linkHover: #004a72; --theme-linkHover: #004a72;
--theme-linkVisited: #53758; --theme-linkVisited: #53758;
--theme-note-reply: rgba(0, 0, 0, 0.04);
} }
[data-bs-theme=dark] { [data-bs-theme=dark] {
@ -175,6 +176,7 @@ $zindex-sticky: 900;
--theme-quoteColor: rgb(141, 144, 150); --theme-quoteColor: rgb(141, 144, 150);
--theme-linkHover: #007cbe; --theme-linkHover: #007cbe;
--theme-linkVisited: #56798E; --theme-linkVisited: #56798E;
--theme-note-reply: rgba(255, 255, 255, 0.06);
} }
@import '../node_modules/bootstrap/scss/bootstrap.scss'; @import '../node_modules/bootstrap/scss/bootstrap.scss';