Compare commits

..

5 Commits

Author SHA1 Message Date
ekzyis
36e9f3f16f
useWallet hook cleanup (#1396)
* Assign everything to wallet object

* Add canReceive for sake of completeness
2024-09-12 11:09:44 -05:00
Keyan
fe0678b4cb
css to put adjacent images/video into vertical alignment (#1387)
* css to put adjacent images/video into vertical alignment

* fix grids chrome

* even grid gap with safari support

* fixes for video and horizontal scroll
2024-09-11 20:10:52 -05:00
ekzyis
0e0fe1af69
Fix duplicate push notification as reply and subscription (#1392) 2024-09-11 16:28:55 -05:00
ekzyis
0bf9fb0780
Fix layout shift between setting tabs (#1390) 2024-09-11 11:14:56 -05:00
k00b
da2fabc95c fix embed styling 2024-09-11 11:10:21 -05:00
7 changed files with 89 additions and 32 deletions

View File

@ -227,7 +227,7 @@ export async function onPaid ({ invoice, id }, context) {
for (const { refereeItem } of item.itemReferrers) { for (const { refereeItem } of item.itemReferrers) {
notifyItemMention({ models, referrerItem: item, refereeItem }).catch(console.error) notifyItemMention({ models, referrerItem: item, refereeItem }).catch(console.error)
} }
notifyUserSubscribers({ models, item }).catch(console.error) notifyUserSubscribers({ models: tx, item }).catch(console.error)
notifyTerritorySubscribers({ models, item }).catch(console.error) notifyTerritorySubscribers({ models, item }).catch(console.error)
} }

View File

@ -22,6 +22,7 @@ import { UNKNOWN_LINK_REL } from '@/lib/constants'
import isEqual from 'lodash/isEqual' import isEqual from 'lodash/isEqual'
import UserPopover from './user-popover' import UserPopover from './user-popover'
import ItemPopover from './item-popover' import ItemPopover from './item-popover'
import classNames from 'classnames'
// Explicitely defined start/end tags & which CSS class from text.module.css to apply // Explicitely defined start/end tags & which CSS class from text.module.css to apply
export const rehypeSuperscript = () => rehypeStyler('<sup>', '</sup>', styles.superscript) export const rehypeSuperscript = () => rehypeStyler('<sup>', '</sup>', styles.superscript)
@ -264,7 +265,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
const rehypePlugins = useMemo(() => [rehypeInlineCodeProperty, rehypeSuperscript, rehypeSubscript], []) const rehypePlugins = useMemo(() => [rehypeInlineCodeProperty, rehypeSuperscript, rehypeSubscript], [])
return ( return (
<div className={`${styles.text} ${show ? styles.textUncontained : overflowing ? styles.textContained : ''}`} ref={containerRef}> <div className={classNames(styles.text, topLevel && styles.topLevel, show ? styles.textUncontained : overflowing && styles.textContained)} ref={containerRef}>
<ReactMarkdown <ReactMarkdown
components={components} components={components}
remarkPlugins={remarkPlugins} remarkPlugins={remarkPlugins}

View File

@ -106,6 +106,12 @@
margin-bottom: .5rem; margin-bottom: .5rem;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
--grid-gap: 0.5rem;
}
.text.topLevel .p {
margin-bottom: 0.75rem;
--grid-gap: 0.75rem;
} }
.text pre { .text pre {
@ -128,17 +134,55 @@
margin-bottom: .5rem; margin-bottom: .5rem;
} }
.text .mediaContainer { .mediaContainer {
display: block; display: block;
margin-top: .5rem;
margin-bottom: .5rem; margin-bottom: .5rem;
width: 100%; width: calc(100% - var(--grid-gap));
max-width: calc(100% - var(--grid-gap));
height: auto; height: auto;
overflow: hidden; overflow: hidden;
max-height: 25vh; max-height: 25vh;
aspect-ratio: var(--aspect-ratio); aspect-ratio: var(--aspect-ratio);
} }
.p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child) {
display: inline-block;
width: min-content;
max-width: calc(100% - var(--grid-gap));
margin-bottom: 0;
}
.mediaContainer ~ .mediaContainer {
display: inline-block;
width: min-content;
margin-right: var(--grid-gap);
}
.p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child) > .mediaContainer:only-child {
margin-right: var(--grid-gap);
}
.p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) {
display: inline-block;
width: min-content;
max-width: calc(100% - var(--grid-gap));
margin-bottom: 0;
}
.p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child {
margin-right: var(--grid-gap);
}
.mediaContainer:has(+ .mediaContainer) {
display: inline-block;
width: min-content;
margin-right: var(--grid-gap);
}
.mediaContainer:first-child:has(+ .mediaContainer) {
margin-top: var(--grid-gap);
}
.mediaContainer img, .mediaContainer video { .mediaContainer img, .mediaContainer video {
display: block; display: block;
object-fit: contain; object-fit: contain;
@ -146,6 +190,7 @@
max-height: inherit; max-height: inherit;
height: 100%; height: 100%;
aspect-ratio: var(--aspect-ratio); aspect-ratio: var(--aspect-ratio);
block-size: stretch;
} }
.mediaContainer img { .mediaContainer img {
@ -155,7 +200,6 @@
} }
.mediaContainer.topLevel { .mediaContainer.topLevel {
margin-top: .75rem;
margin-bottom: .75rem; margin-bottom: .75rem;
max-height: 35vh; max-height: 35vh;
} }
@ -190,7 +234,7 @@ img.fullScreen {
margin-bottom: 0; margin-bottom: 0;
} }
.text li+li { .text li {
margin-top: .25rem; margin-top: .25rem;
} }
@ -260,12 +304,12 @@ img.fullScreen {
.videoWrapper { .videoWrapper {
max-width: 320px; max-width: 320px;
padding-right: 15px; margin: 0.5rem 0;
margin: '0.5rem 0',
} }
.videoWrapper.topLevel { .videoWrapper.topLevel {
max-width: 640px; max-width: 640px;
margin: 0.75rem 0;
} }
.videoContainer { .videoContainer {

View File

@ -129,7 +129,15 @@ export const notifyUserSubscribers = async ({ models, item }) => {
INNER JOIN users ON users.id = "UserSubscription"."followeeId" INNER JOIN users ON users.id = "UserSubscription"."followeeId"
WHERE "followeeId" = $1 AND ${isPost ? '"postsSubscribedAt"' : '"commentsSubscribedAt"'} IS NOT NULL WHERE "followeeId" = $1 AND ${isPost ? '"postsSubscribedAt"' : '"commentsSubscribedAt"'} IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM "Mute" WHERE "Mute"."muterId" = "UserSubscription"."followerId" AND "Mute"."mutedId" = $1) AND NOT EXISTS (SELECT 1 FROM "Mute" WHERE "Mute"."muterId" = "UserSubscription"."followerId" AND "Mute"."mutedId" = $1)
`, Number(item.userId)) -- ignore subscription if user was already notified of item as a reply
AND NOT EXISTS (
SELECT 1 FROM "Reply"
INNER JOIN users follower ON follower.id = "UserSubscription"."followerId"
WHERE "Reply"."itemId" = $2
AND "Reply"."ancestorUserId" = follower.id
AND follower."noteAllDescendants"
)
`, Number(item.userId), Number(item.id))
const subType = isPost ? 'POST' : 'COMMENT' const subType = isPost ? 'POST' : 'COMMENT'
const tag = `FOLLOW-${item.userId}-${subType}` const tag = `FOLLOW-${item.userId}-${subType}`
await Promise.allSettled(userSubsExcludingMutes.map(({ followerId, followeeName }) => sendUserNotification(followerId, { await Promise.allSettled(userSubsExcludingMutes.map(({ followerId, followeeName }) => sendUserNotification(followerId, {

View File

@ -107,8 +107,8 @@ export default function Settings ({ ssrData }) {
return ( return (
<Layout> <Layout>
<div className='pb-3 w-100 mt-2' style={{ maxWidth: '600px' }}> <div className='pb-3 w-100 mt-2' style={{ maxWidth: '600px' }}>
{hasOnlyOneAuthMethod(settings?.authMethods) && <AuthBanner />}
<SettingsHeader /> <SettingsHeader />
{hasOnlyOneAuthMethod(settings?.authMethods) && <AuthBanner />}
<Form <Form
initial={{ initial={{
tipDefault: settings?.tipDefault || 21, tipDefault: settings?.tipDefault || 21,

View File

@ -17,6 +17,7 @@
.fullItemContainer { .fullItemContainer {
margin-bottom: .5rem; margin-bottom: .5rem;
padding-right: 15px;
} }
.fullItemContainer:empty { .fullItemContainer:empty {

View File

@ -45,12 +45,6 @@ export function useWallet (name) {
logger.info('payments disabled') logger.info('payments disabled')
}, [name, me, logger]) }, [name, me, logger])
if (wallet) {
wallet.isConfigured = _isConfigured
wallet.enablePayments = enablePayments
wallet.disablePayments = disablePayments
}
const status = config?.enabled ? Status.Enabled : Status.Initialized const status = config?.enabled ? Status.Enabled : Status.Initialized
const enabled = status === Status.Enabled const enabled = status === Status.Enabled
const priority = config?.priority const priority = config?.priority
@ -95,21 +89,30 @@ export function useWallet (name) {
if (!wallet) return null if (!wallet) return null
return { // Assign everything to wallet object so every function that is passed this wallet object in this
...wallet, // `useWallet` hook has access to all others via the reference to it.
canSend: !!wallet.sendPayment, // Essentially, you can now use functions like `enablePayments` _inside_ of functions that are
sendPayment, // called by `useWallet` even before enablePayments is defined and not only in functions
config, // that use the return value of `useWallet`.
save, wallet.isConfigured = _isConfigured
delete: delete_, wallet.enablePayments = enablePayments
deleteLogs, wallet.disablePayments = disablePayments
setPriority, wallet.canSend = !!wallet.sendPayment
hasConfig, wallet.canReceive = !!wallet.createInvoice
status, wallet.config = config
enabled, wallet.save = save
priority, wallet.delete = delete_
logger wallet.deleteLogs = deleteLogs
} wallet.setPriority = setPriority
wallet.hasConfig = hasConfig
wallet.status = status
wallet.enabled = enabled
wallet.priority = priority
wallet.logger = logger
// can't assign sendPayment to wallet object because it already exists
// as an imported function and thus can't be overwritten
return { ...wallet, sendPayment }
} }
function extractConfig (fields, config, client) { function extractConfig (fields, config, client) {