Compare commits

..

No commits in common. "ae579cbec3f491a96960b3f0cc748db8d3eace63" and "be7ea41d03ce26b0a7e1252cacc1298b9687efbb" have entirely different histories.

10 changed files with 82 additions and 112 deletions

View File

@ -370,7 +370,6 @@ export default {
${relationClause(type)} ${relationClause(type)}
${whereClause( ${whereClause(
'"Item".created_at <= $1', '"Item".created_at <= $1',
'"Item"."deletedAt" IS NULL',
subClause(sub, 4, subClauseTable(type), me, showNsfw), subClause(sub, 4, subClauseTable(type), me, showNsfw),
activeOrMine(me), activeOrMine(me),
await filterClause(me, models, type), await filterClause(me, models, type),
@ -450,7 +449,6 @@ export default {
FROM "Item" FROM "Item"
${whereClause( ${whereClause(
'"parentId" IS NULL', '"parentId" IS NULL',
'"Item"."deletedAt" IS NULL',
'created_at <= $1', 'created_at <= $1',
'"pinId" IS NULL', '"pinId" IS NULL',
subClause(sub, 4), subClause(sub, 4),
@ -476,7 +474,6 @@ export default {
sub ? '"Item"."pinId" IS NULL' : '', sub ? '"Item"."pinId" IS NULL' : '',
'"Item"."deletedAt" IS NULL', '"Item"."deletedAt" IS NULL',
'"Item"."parentId" IS NULL', '"Item"."parentId" IS NULL',
'"Item".outlawed = false',
'"Item".bio = false', '"Item".bio = false',
activeOrMine(me), activeOrMine(me),
subClause(sub, 3, 'Item', me, showNsfw), subClause(sub, 3, 'Item', me, showNsfw),

View File

@ -124,6 +124,3 @@ riccardobl,pr,#1293,#1142,medium,high,,,500k,rblb@getalby.com,2024-08-18
tsmith123,pr,#1306,#832,medium,,,,250k,stickymarch60@walletofsatoshi.com,2024-08-20 tsmith123,pr,#1306,#832,medium,,,,250k,stickymarch60@walletofsatoshi.com,2024-08-20
riccardobl,pr,#1311,#864,medium,high,,pending unrelated refactor,500k,rblb@getalby.com,2024-08-27 riccardobl,pr,#1311,#864,medium,high,,pending unrelated refactor,500k,rblb@getalby.com,2024-08-27
brugeman,issue,#1311,#864,medium,high,,,50k,brugeman@stacker.news,2024-08-27 brugeman,issue,#1311,#864,medium,high,,,50k,brugeman@stacker.news,2024-08-27
riccardobl,pr,#1342,#1141,hard,high,,pending unrelated rearchitecture,1m,rblb@getalby.com,2024-09-09
SatsAllDay,issue,#1368,#1331,medium,,,,25k,weareallsatoshi@getalby.com,2024-09-16
benalleng,helpfulness,#1368,#1170,medium,,,did a lot of it in #1175,25k,BenAllenG@stacker.news,2024-09-16

1 name type pr id issue ids difficulty priority changes requested notes amount receive method date paid
124 tsmith123 pr #1306 #832 medium 250k stickymarch60@walletofsatoshi.com 2024-08-20
125 riccardobl pr #1311 #864 medium high pending unrelated refactor 500k rblb@getalby.com 2024-08-27
126 brugeman issue #1311 #864 medium high 50k brugeman@stacker.news 2024-08-27
riccardobl pr #1342 #1141 hard high pending unrelated rearchitecture 1m rblb@getalby.com 2024-09-09
SatsAllDay issue #1368 #1331 medium 25k weareallsatoshi@getalby.com 2024-09-16
benalleng helpfulness #1368 #1170 medium did a lot of it in #1175 25k BenAllenG@stacker.news 2024-09-16

View File

@ -14,7 +14,7 @@ export default function Hat ({ user, badge, className = 'ms-1', height = 16, wid
{badge {badge
? ( ? (
<Badge bg='grey-medium' className='ms-2 d-inline-flex align-items-center'> <Badge bg='grey-medium' className='ms-2 d-inline-flex align-items-center'>
<AnonIcon className={`${className} fill-dark align-middle`} height={height} width={width} /> <AnonIcon className={`${className} align-middle`} height={height} width={width} />
</Badge>) </Badge>)
: <span><AnonIcon className={`${className} align-middle`} height={height} width={width} /></span>} : <span><AnonIcon className={`${className} align-middle`} height={height} width={width} /></span>}
</HatTooltip> </HatTooltip>
@ -34,7 +34,7 @@ export default function Hat ({ user, badge, className = 'ms-1', height = 16, wid
{badge {badge
? ( ? (
<Badge bg='grey-medium' className='ms-2 d-inline-flex align-items-center'> <Badge bg='grey-medium' className='ms-2 d-inline-flex align-items-center'>
<CowboyHatIcon className={`${className} fill-dark`} height={height} width={width} /> <CowboyHatIcon className={className} height={height} width={width} />
<span className='ms-1 text-dark'>{streak || 'new'}</span> <span className='ms-1 text-dark'>{streak || 'new'}</span>
</Badge>) </Badge>)
: <span><CowboyHatIcon className={className} height={height} width={width} /></span>} : <span><CowboyHatIcon className={className} height={height} width={width} /></span>}

View File

@ -23,7 +23,6 @@ import { decodeProxyUrl, IMGPROXY_URL_REGEXP } from '@/lib/url'
import { numWithUnits } from '@/lib/format' import { numWithUnits } from '@/lib/format'
import { useQuoteReply } from './use-quote-reply' import { useQuoteReply } from './use-quote-reply'
import { UNKNOWN_LINK_REL } from '@/lib/constants' import { UNKNOWN_LINK_REL } from '@/lib/constants'
import classNames from 'classnames'
function BioItem ({ item, handleClick }) { function BioItem ({ item, handleClick }) {
const { me } = useMe() const { me } = useMe()
@ -90,7 +89,7 @@ function TopLevelItem ({ item, noReply, ...props }) {
belowTitle={item.forwards && item.forwards.length > 0 && <FwdUsers forwards={item.forwards} />} belowTitle={item.forwards && item.forwards.length > 0 && <FwdUsers forwards={item.forwards} />}
{...props} {...props}
> >
<article className={classNames(styles.fullItemContainer, 'topLevel')} ref={textRef}> <article className={styles.fullItemContainer} ref={textRef}>
{item.text && <ItemText item={item} />} {item.text && <ItemText item={item} />}
{item.url && !item.outlawed && <ItemEmbed url={item.url} imgproxyUrls={item.imgproxyUrls} />} {item.url && !item.outlawed && <ItemEmbed url={item.url} imgproxyUrls={item.imgproxyUrls} />}
{item.poll && <Poll item={item} />} {item.poll && <Poll item={item} />}

View File

@ -93,7 +93,8 @@ export default function MediaOrLink ({ linkFallback = true, ...props }) {
if (media.embed) { if (media.embed) {
return ( return (
<Embed <Embed
{...media.embed} topLevel={props.topLevel} src={media.src} onError={handleError} {...media.embed} src={media.src}
className={media.className} onError={handleError} topLevel={props.topLevel}
/> />
) )
} }
@ -122,15 +123,19 @@ export const useMediaHelper = ({ src, srcSet: srcSetIntital, topLevel, tab }) =>
// make sure it's not a false negative by trying to load URL as <img> // make sure it's not a false negative by trying to load URL as <img>
const img = new window.Image() const img = new window.Image()
img.onload = () => setIsImage(true) img.onload = () => setIsImage(true)
img.onerror = () => setIsImage(false)
img.src = src img.src = src
const video = document.createElement('video') const video = document.createElement('video')
video.onloadeddata = () => setIsVideo(true) video.onloadeddata = () => setIsVideo(true)
video.onerror = () => setIsVideo(false)
video.src = src video.src = src
return () => { return () => {
img.onload = null img.onload = null
img.onerror = null
img.src = '' img.src = ''
video.onloadeddata = null video.onloadeddata = null
video.onerror = null
video.src = '' video.src = ''
} }
}, [src, setIsImage, setIsVideo, showMedia, isVideo, embed]) }, [src, setIsImage, setIsVideo, showMedia, isVideo, embed])
@ -182,6 +187,7 @@ export const useMediaHelper = ({ src, srcSet: srcSetIntital, topLevel, tab }) =>
style, style,
width, width,
height, height,
className: classNames(topLevel && styles.topLevel),
image: (!me?.privates?.imgproxyOnly || trusted) && showMedia && isImage && !isVideo && !embed, image: (!me?.privates?.imgproxyOnly || trusted) && showMedia && isImage && !isVideo && !embed,
video: !me?.privates?.imgproxyOnly && showMedia && isVideo && !embed, video: !me?.privates?.imgproxyOnly && showMedia && isVideo && !embed,
embed: !me?.privates?.imgproxyOnly && showMedia && embed embed: !me?.privates?.imgproxyOnly && showMedia && embed

View File

@ -5,7 +5,7 @@ import TocIcon from '@/svgs/list-unordered.svg'
import { fromMarkdown } from 'mdast-util-from-markdown' import { fromMarkdown } from 'mdast-util-from-markdown'
import { visit } from 'unist-util-visit' import { visit } from 'unist-util-visit'
import { toString } from 'mdast-util-to-string' import { toString } from 'mdast-util-to-string'
import { slug } from 'github-slugger' import GithubSlugger from 'github-slugger'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
export default function Toc ({ text }) { export default function Toc ({ text }) {
@ -17,11 +17,11 @@ export default function Toc ({ text }) {
const toc = useMemo(() => { const toc = useMemo(() => {
const tree = fromMarkdown(text) const tree = fromMarkdown(text)
const toc = [] const toc = []
const slugger = new GithubSlugger()
visit(tree, 'heading', (node, position, parent) => { visit(tree, 'heading', (node, position, parent) => {
const str = toString(node) const str = toString(node)
toc.push({ heading: str, slug: slug(str.replace(/[^\w\-\s]+/gi, '')), depth: node.depth }) toc.push({ heading: str, slug: slugger.slug(str.replace(/[^\w\-\s]+/gi, '')), depth: node.depth })
}) })
return toc return toc
}, [text]) }, [text])

View File

@ -6,7 +6,7 @@ import atomDark from 'react-syntax-highlighter/dist/cjs/styles/prism/atom-dark'
import mention from '@/lib/remark-mention' import mention from '@/lib/remark-mention'
import sub from '@/lib/remark-sub' import sub from '@/lib/remark-sub'
import React, { useState, memo, useRef, useCallback, useMemo, useEffect } from 'react' import React, { useState, memo, useRef, useCallback, useMemo, useEffect } from 'react'
import { slug } from 'github-slugger' import GithubSlugger from 'github-slugger'
import LinkIcon from '@/svgs/link.svg' import LinkIcon from '@/svgs/link.svg'
import Thumb from '@/svgs/thumb-up-fill.svg' import Thumb from '@/svgs/thumb-up-fill.svg'
import { toString } from 'mdast-util-to-string' import { toString } from 'mdast-util-to-string'
@ -82,10 +82,12 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
} }
}, [containerRef.current, setOverflowing]) }, [containerRef.current, setOverflowing])
const slugger = useMemo(() => new GithubSlugger(), [])
const Heading = useCallback(({ children, node, ...props }) => { const Heading = useCallback(({ children, node, ...props }) => {
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
const nodeText = toString(node) const nodeText = toString(node)
const id = useMemo(() => noFragments ? undefined : slug(nodeText.replace(/[^\w\-\s]+/gi, '')), [nodeText, noFragments]) const id = useMemo(() => noFragments ? undefined : slugger?.slug(nodeText.replace(/[^\w\-\s]+/gi, '')), [nodeText, noFragments, slugger])
const h = useMemo(() => { const h = useMemo(() => {
if (topLevel) { if (topLevel) {
return node?.TagName return node?.TagName
@ -118,7 +120,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
</a>} </a>}
</span> </span>
) )
}, [topLevel, noFragments]) }, [topLevel, noFragments, slugger])
const Table = useCallback(({ node, ...props }) => const Table = useCallback(({ node, ...props }) =>
<span className='table-responsive'> <span className='table-responsive'>

View File

@ -6,7 +6,6 @@
overflow-y: hidden; overflow-y: hidden;
position: relative; position: relative;
max-height: 200vh; max-height: 200vh;
--grid-gap: 0.5rem;
} }
@ -99,75 +98,45 @@
} }
.text hr { .text hr {
border-top: 3px solid var(--theme-quoteBar); border-top: 1px solid var(--theme-clickToContextColor);
}
.text.topLevel {
--grid-gap: 0.75rem;
} }
.text .p { .text .p {
display: block; display: block;
margin-bottom: .5rem;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
padding-top: .25rem; --grid-gap: 0.5rem;
padding-bottom: .25rem;
} }
.text.topLevel .p { .text.topLevel .p {
padding-top: .375rem; margin-bottom: 0.75rem;
padding-bottom: .375rem; --grid-gap: 0.75rem;
} }
.text>*:not(.heading) { .text pre {
padding-top: .25rem; margin-bottom: .5rem;
padding-bottom: .25rem;
}
.text.topLevel>*:not(.heading) {
padding-top: .375rem;
padding-bottom: .375rem;
}
.text pre, .text blockquote {
margin-top: .25rem;
margin-bottom: .25rem;
}
.text.topLevel pre, .text.topLevel blockquote {
margin-top: .375rem;
margin-bottom: .375rem;
} }
.text pre>div { .text pre>div {
margin: 0 !important; margin: 0 !important;
} }
.text>*:last-child:not(.textShowFull) { .text>*:last-child {
padding-bottom: 0 !important;
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.text>*:first-child { .text blockquote:last-child {
padding-top: 0 !important; margin-bottom: 0 !important;
margin-top: 0 !important;
} }
.text blockquote, .text.topLevel blockquote { .text blockquote:has(+ :not(blockquote)) {
padding-top: 0 !important; margin-bottom: .5rem;
padding-bottom: 0 !important;
}
.text blockquote *:first-child, .text.topLevel blockquote *:first-child {
padding-top: 0;
}
.text blockquote *:last-child, .text.topLevel blockquote *:last-child {
padding-bottom: 0;
} }
.mediaContainer { .mediaContainer {
display: block; display: block;
margin-bottom: .5rem;
width: calc(100% - var(--grid-gap)); width: calc(100% - var(--grid-gap));
max-width: calc(100% - var(--grid-gap)); max-width: calc(100% - var(--grid-gap));
height: auto; height: auto;
@ -178,40 +147,44 @@
.p:has(> .mediaContainer) { .p:has(> .mediaContainer) {
white-space: normal; white-space: normal;
padding: 0 !important;
} }
.p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child), .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) { .p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) {
display: inline-block; display: inline-block;
width: min-content; width: min-content;
max-width: calc(100% - var(--grid-gap)); max-width: calc(100% - var(--grid-gap));
margin-bottom: 0;
} }
.mediaContainer ~ .mediaContainer, .mediaContainer:has(+ .mediaContainer) { .p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child {
margin-right: var(--grid-gap);
}
.mediaContainer:has(+ .mediaContainer) {
display: inline-block; display: inline-block;
width: min-content; width: min-content;
margin-right: var(--grid-gap); margin-right: var(--grid-gap);
} }
.p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child) > .mediaContainer:only-child, .mediaContainer:first-child:has(+ .mediaContainer) {
.p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child, margin-top: var(--grid-gap);
.mediaContainer:first-child:has(+ .mediaContainer) {
margin-right: var(--grid-gap);
}
.p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child) > .mediaContainer:only-child img,
.p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child img,
.mediaContainer ~ .mediaContainer img,
.mediaContainer:has(+ .mediaContainer) img {
block-size: revert-layer;
max-width: stretch;
}
.p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child) > .mediaContainer:only-child video,
.p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child video,
.mediaContainer ~ .mediaContainer video,
.mediaContainer:has(+ .mediaContainer) video {
block-size: stretch;
} }
.mediaContainer img, .mediaContainer video { .mediaContainer img, .mediaContainer video {
@ -221,6 +194,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 {
@ -229,7 +203,8 @@
object-position: left top; object-position: left top;
} }
.topLevel .mediaContainer, :global(.topLevel) .mediaContainer { .mediaContainer.topLevel {
margin-bottom: .75rem;
max-height: 35vh; max-height: 35vh;
} }
@ -258,8 +233,9 @@ img.fullScreen {
} }
.text blockquote { .text blockquote {
border-left: 3px solid var(--theme-quoteBar); border-left: 2px solid var(--theme-quoteBar);
padding-left: .75rem; padding-left: .75rem;
margin-bottom: 0;
} }
.text li { .text li {
@ -269,10 +245,19 @@ img.fullScreen {
.text ul, .text ul,
.text ol { .text ol {
margin-top: 0; margin-top: 0;
margin-bottom: 0rem; margin-bottom: 1rem;
padding-left: 2rem; padding-left: 2rem;
} }
.text ul:last-child, .text ol:last-child {
margin-bottom: 0;
}
.text li > .p {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.text ol ol, .text ol ol,
.text ul ol { .text ul ol {
list-style-type: lower-roman; list-style-type: lower-roman;
@ -285,11 +270,6 @@ img.fullScreen {
list-style-type: lower-alpha; list-style-type: lower-alpha;
} }
.text h1, .text h2, .text h3, .text h4, .text h5, .text h6 {
margin-top: 0.75rem;
margin-bottom: 0.5rem;
}
.text h1 { .text h1 {
font-size: 1.6rem; font-size: 1.6rem;
} }
@ -326,24 +306,12 @@ img.fullScreen {
font-size: smaller; font-size: smaller;
} }
.twitterContainer, .nostrContainer, .videoWrapper, .wavlakeWrapper, .spotifyWrapper, .mediaContainer {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.topLevel .twitterContainer, .topLevel .nostrContainer, .topLevel .videoWrapper,
.topLevel .wavlakeWrapper, .topLevel .spotifyWrapper, .topLevel .mediaContainer,
:global(.topLevel) .twitterContainer, :global(.topLevel) .nostrContainer, :global(.topLevel) .videoWrapper,
:global(.topLevel) .wavlakeWrapper, :global(.topLevel) .spotifyWrapper, :global(.topLevel) .mediaContainer {
margin-top: 0.375rem;
margin-bottom: 0.375rem;
}
.videoWrapper { .videoWrapper {
max-width: 320px; max-width: 320px;
margin: 0.5rem 0;
} }
.topLevel .videoWrapper, :global(.topLevel) .videoWrapper { .videoWrapper.topLevel {
max-width: 640px; max-width: 640px;
margin: 0.75rem 0; margin: 0.75rem 0;
} }
@ -365,10 +333,15 @@ img.fullScreen {
} }
.twitterContainer, .nostrContainer { .twitterContainer, .nostrContainer {
margin-top: .25rem;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
.twitterContainer:not(:first-child), .nostrContainer:not(:first-child) {
margin-top: .75rem;
}
.twitterContainer iframe, .nostrContainer iframe { .twitterContainer iframe, .nostrContainer iframe {
border-radius: 13px; border-radius: 13px;
} }
@ -386,7 +359,7 @@ img.fullScreen {
overflow: hidden; overflow: hidden;
} }
.topLevel .twitterContained, :global(.topLevel) .twitterContained { .twitterContained.topLevel {
height: 200px; height: 200px;
} }
@ -407,7 +380,7 @@ img.fullScreen {
padding-right: 12px; padding-right: 12px;
} }
.topLevel .tweetsSkeleton, :global(.topLevel) .tweetsSkeleton { .tweetsSkeleton.topLevel {
max-width: 550px; max-width: 550px;
} }
@ -422,7 +395,7 @@ img.fullScreen {
padding: 1.5rem; padding: 1.5rem;
} }
.topLevel .tweetSkeleton, :global(.topLevel) .tweetSkeleton { .topLevel .tweetSkeleton {
height: 200px; height: 200px;
} }

View File

@ -92,7 +92,7 @@ async function bountyWinner (q) {
const bounty = await client.query({ const bounty = await client.query({
query: SEARCH, query: SEARCH,
variables: { q: `${q} @sn`, sort: 'recent', what: 'posts', when: 'week' } variables: { q: `${q} @grayruby`, sort: 'recent', what: 'posts', when: 'week' }
}) })
const items = bounty.data.search.items.filter(i => i.bountyPaidTo?.length > 0) const items = bounty.data.search.items.filter(i => i.bountyPaidTo?.length > 0)

View File

@ -784,10 +784,6 @@ div[contenteditable]:focus,
fill: white; fill: white;
} }
.fill-dark {
fill: #212529;
}
.fill-success { .fill-success {
fill: var(--bs-success); fill: var(--bs-success);
} }