Compare commits

...

12 Commits

Author SHA1 Message Date
k00b ae579cbec3 remove mod outlaws from hot 2024-09-16 13:30:40 -05:00
Keyan a5af2538c6
Update awards.csv 2024-09-16 12:11:15 -05:00
k00b d46ae03598 attempt to fix img shift 2024-09-16 12:00:15 -05:00
k00b e63609a7c1 don't show deleted items in main sorts 2024-09-16 11:57:16 -05:00
k00b 404cb0aaa7 fixes for toplevel media embeds 2024-09-16 11:54:22 -05:00
k00b d9213da268 fix overflowed image 2024-09-14 19:25:25 -05:00
k00b 12d2e99576 fix inline image shrinking 2024-09-14 18:22:11 -05:00
k00b 88eea9ca94 newsletter script: search for bounties on @sn account 2024-09-14 13:44:57 -05:00
k00b df65104c60 fix text/media component styling 2024-09-13 20:40:40 -05:00
k00b 2018cc1f0b fix image height in certain contexts 2024-09-13 19:14:49 -05:00
ekzyis 7c68eafa56
Fix hat contrast in profile in dark mode (#1406) 2024-09-13 19:05:16 -05:00
ekzyis 85a8fc5dcd
Fix different slugs generated in ToC vs text (#1405) 2024-09-13 15:54:30 -05:00
10 changed files with 114 additions and 84 deletions

View File

@ -370,6 +370,7 @@ 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),
@ -449,6 +450,7 @@ 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),
@ -474,6 +476,7 @@ 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,3 +124,6 @@ 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
127 riccardobl pr #1342 #1141 hard high pending unrelated rearchitecture 1m rblb@getalby.com 2024-09-09
128 SatsAllDay issue #1368 #1331 medium 25k weareallsatoshi@getalby.com 2024-09-16
129 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} align-middle`} height={height} width={width} /> <AnonIcon className={`${className} fill-dark 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} height={height} width={width} /> <CowboyHatIcon className={`${className} fill-dark`} 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,6 +23,7 @@ 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()
@ -89,7 +90,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={styles.fullItemContainer} ref={textRef}> <article className={classNames(styles.fullItemContainer, 'topLevel')} 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,8 +93,7 @@ export default function MediaOrLink ({ linkFallback = true, ...props }) {
if (media.embed) { if (media.embed) {
return ( return (
<Embed <Embed
{...media.embed} src={media.src} {...media.embed} topLevel={props.topLevel} src={media.src} onError={handleError}
className={media.className} onError={handleError} topLevel={props.topLevel}
/> />
) )
} }
@ -123,19 +122,15 @@ 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])
@ -187,7 +182,6 @@ 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 GithubSlugger from 'github-slugger' import { slug } 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: slugger.slug(str.replace(/[^\w\-\s]+/gi, '')), depth: node.depth }) toc.push({ heading: str, slug: 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 GithubSlugger from 'github-slugger' import { slug } 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,12 +82,10 @@ 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 : slugger?.slug(nodeText.replace(/[^\w\-\s]+/gi, '')), [nodeText, noFragments, slugger]) const id = useMemo(() => noFragments ? undefined : slug(nodeText.replace(/[^\w\-\s]+/gi, '')), [nodeText, noFragments])
const h = useMemo(() => { const h = useMemo(() => {
if (topLevel) { if (topLevel) {
return node?.TagName return node?.TagName
@ -120,7 +118,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
</a>} </a>}
</span> </span>
) )
}, [topLevel, noFragments, slugger]) }, [topLevel, noFragments])
const Table = useCallback(({ node, ...props }) => const Table = useCallback(({ node, ...props }) =>
<span className='table-responsive'> <span className='table-responsive'>

View File

@ -6,6 +6,7 @@
overflow-y: hidden; overflow-y: hidden;
position: relative; position: relative;
max-height: 200vh; max-height: 200vh;
--grid-gap: 0.5rem;
} }
@ -98,45 +99,75 @@
} }
.text hr { .text hr {
border-top: 1px solid var(--theme-clickToContextColor); border-top: 3px solid var(--theme-quoteBar);
}
.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;
--grid-gap: 0.5rem; padding-top: .25rem;
padding-bottom: .25rem;
} }
.text.topLevel .p { .text.topLevel .p {
margin-bottom: 0.75rem; padding-top: .375rem;
--grid-gap: 0.75rem; padding-bottom: .375rem;
} }
.text pre { .text>*:not(.heading) {
margin-bottom: .5rem; padding-top: .25rem;
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 { .text>*:last-child:not(.textShowFull) {
padding-bottom: 0 !important;
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.text blockquote:last-child { .text>*:first-child {
margin-bottom: 0 !important; padding-top: 0 !important;
margin-top: 0 !important;
} }
.text blockquote:has(+ :not(blockquote)) { .text blockquote, .text.topLevel blockquote {
margin-bottom: .5rem; padding-top: 0 !important;
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;
@ -147,44 +178,40 @@
.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;
} }
.p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child { .mediaContainer ~ .mediaContainer, .mediaContainer:has(+ .mediaContainer) {
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);
} }
.mediaContainer:first-child:has(+ .mediaContainer) { .p:has(> .mediaContainer:only-child) ~ .p:has(> .mediaContainer:only-child) > .mediaContainer:only-child,
margin-top: var(--grid-gap); .p:has(> .mediaContainer:only-child):has(+ .p > .mediaContainer:only-child) > .mediaContainer:only-child,
.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 {
@ -194,7 +221,6 @@
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 {
@ -203,8 +229,7 @@
object-position: left top; object-position: left top;
} }
.mediaContainer.topLevel { .topLevel .mediaContainer, :global(.topLevel) .mediaContainer {
margin-bottom: .75rem;
max-height: 35vh; max-height: 35vh;
} }
@ -233,9 +258,8 @@ img.fullScreen {
} }
.text blockquote { .text blockquote {
border-left: 2px solid var(--theme-quoteBar); border-left: 3px solid var(--theme-quoteBar);
padding-left: .75rem; padding-left: .75rem;
margin-bottom: 0;
} }
.text li { .text li {
@ -245,19 +269,10 @@ img.fullScreen {
.text ul, .text ul,
.text ol { .text ol {
margin-top: 0; margin-top: 0;
margin-bottom: 1rem; margin-bottom: 0rem;
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;
@ -270,6 +285,11 @@ 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;
} }
@ -306,12 +326,24 @@ img.fullScreen {
font-size: smaller; font-size: smaller;
} }
.videoWrapper { .twitterContainer, .nostrContainer, .videoWrapper, .wavlakeWrapper, .spotifyWrapper, .mediaContainer {
max-width: 320px; margin-top: 0.25rem;
margin: 0.5rem 0; margin-bottom: 0.25rem;
} }
.videoWrapper.topLevel { .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 {
max-width: 320px;
}
.topLevel .videoWrapper, :global(.topLevel) .videoWrapper {
max-width: 640px; max-width: 640px;
margin: 0.75rem 0; margin: 0.75rem 0;
} }
@ -333,15 +365,10 @@ 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;
} }
@ -359,7 +386,7 @@ img.fullScreen {
overflow: hidden; overflow: hidden;
} }
.twitterContained.topLevel { .topLevel .twitterContained, :global(.topLevel) .twitterContained {
height: 200px; height: 200px;
} }
@ -380,7 +407,7 @@ img.fullScreen {
padding-right: 12px; padding-right: 12px;
} }
.tweetsSkeleton.topLevel { .topLevel .tweetsSkeleton, :global(.topLevel) .tweetsSkeleton {
max-width: 550px; max-width: 550px;
} }
@ -395,7 +422,7 @@ img.fullScreen {
padding: 1.5rem; padding: 1.5rem;
} }
.topLevel .tweetSkeleton { .topLevel .tweetSkeleton, :global(.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} @grayruby`, sort: 'recent', what: 'posts', when: 'week' } variables: { q: `${q} @sn`, 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,6 +784,10 @@ div[contenteditable]:focus,
fill: white; fill: white;
} }
.fill-dark {
fill: #212529;
}
.fill-success { .fill-success {
fill: var(--bs-success); fill: var(--bs-success);
} }