Merge branch 'high'
This commit is contained in:
commit
80b8744b8e
|
@ -11,7 +11,7 @@ async function comments (models, id, sort) {
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case 'top':
|
case 'top':
|
||||||
orderBy = 'ORDER BY x.sats DESC NULLS LAST'
|
orderBy = 'ORDER BY x.sats DESC NULLS LAST'
|
||||||
join = LEFT_JOIN_SATS
|
join = LEFT_JOIN_WEIGHTED_SATS
|
||||||
break
|
break
|
||||||
case 'recent':
|
case 'recent':
|
||||||
orderBy = 'ORDER BY "Item".created_at DESC'
|
orderBy = 'ORDER BY "Item".created_at DESC'
|
||||||
|
@ -19,7 +19,7 @@ async function comments (models, id, sort) {
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
orderBy = ORDER_BY_SATS
|
orderBy = ORDER_BY_SATS
|
||||||
join = LEFT_JOIN_SATS
|
join = LEFT_JOIN_WEIGHTED_SATS
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ export default {
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
${SELECT}
|
${SELECT}
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
${timedLeftJoinSats(1)}
|
${timedLeftJoinWeightedSats(1)}
|
||||||
WHERE "parentId" IS NULL AND created_at <= $1 AND created_at > $3
|
WHERE "parentId" IS NULL AND created_at <= $1 AND created_at > $3
|
||||||
AND "pinId" IS NULL
|
AND "pinId" IS NULL
|
||||||
${timedOrderBySats(1)}
|
${timedOrderBySats(1)}
|
||||||
|
@ -121,7 +121,7 @@ export default {
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
${SELECT}
|
${SELECT}
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
${timedLeftJoinSats(1)}
|
${timedLeftJoinWeightedSats(1)}
|
||||||
WHERE "parentId" IS NULL AND created_at <= $1
|
WHERE "parentId" IS NULL AND created_at <= $1
|
||||||
AND "pinId" IS NULL
|
AND "pinId" IS NULL
|
||||||
${timedOrderBySats(1)}
|
${timedOrderBySats(1)}
|
||||||
|
@ -143,17 +143,6 @@ export default {
|
||||||
) rank_filter WHERE RANK = 1`)
|
) rank_filter WHERE RANK = 1`)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'wot':
|
|
||||||
items = await models.$queryRaw(`
|
|
||||||
${SELECT}
|
|
||||||
FROM "Item"
|
|
||||||
${timedLeftJoinWeightedSats(1)}
|
|
||||||
WHERE "parentId" IS NULL AND created_at <= $1
|
|
||||||
AND "pinId" IS NULL
|
|
||||||
${timedOrderBySats(1)}
|
|
||||||
OFFSET $2
|
|
||||||
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
|
||||||
break
|
|
||||||
case 'top':
|
case 'top':
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
${SELECT}
|
${SELECT}
|
||||||
|
@ -290,6 +279,16 @@ export default {
|
||||||
must: {
|
must: {
|
||||||
bool: {
|
bool: {
|
||||||
should: [
|
should: [
|
||||||
|
{
|
||||||
|
// all terms are matched in fields
|
||||||
|
multi_match: {
|
||||||
|
query,
|
||||||
|
type: 'most_fields',
|
||||||
|
fields: ['title^20', 'text'],
|
||||||
|
minimum_should_match: '100%',
|
||||||
|
boost: 400
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// all terms are matched in fields
|
// all terms are matched in fields
|
||||||
multi_match: {
|
multi_match: {
|
||||||
|
@ -299,7 +298,7 @@ export default {
|
||||||
fuzziness: 'AUTO',
|
fuzziness: 'AUTO',
|
||||||
prefix_length: 3,
|
prefix_length: 3,
|
||||||
minimum_should_match: '100%',
|
minimum_should_match: '100%',
|
||||||
boost: 2
|
boost: 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -309,6 +308,7 @@ export default {
|
||||||
type: 'most_fields',
|
type: 'most_fields',
|
||||||
fields: ['title^20', 'text'],
|
fields: ['title^20', 'text'],
|
||||||
fuzziness: 'AUTO',
|
fuzziness: 'AUTO',
|
||||||
|
prefix_length: 3,
|
||||||
minimum_should_match: '60%'
|
minimum_should_match: '60%'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,6 +325,12 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
fields: {
|
||||||
|
title: { number_of_fragments: 0, pre_tags: [':high['], post_tags: [']'] },
|
||||||
|
text: { number_of_fragments: 0, pre_tags: [':high['], post_tags: [']'] }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -336,7 +342,16 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = sitems.body.hits.hits.map(e => e._source)
|
// return highlights
|
||||||
|
const items = sitems.body.hits.hits.map(e => {
|
||||||
|
const item = e._source
|
||||||
|
|
||||||
|
item.searchTitle = (e.highlight.title && e.highlight.title[0]) || item.title
|
||||||
|
item.searchText = (e.highlight.text && e.highlight.text[0]) || item.text
|
||||||
|
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursor: items.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
cursor: items.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
||||||
items
|
items
|
||||||
|
@ -730,12 +745,18 @@ function timedLeftJoinWeightedSats (num) {
|
||||||
) x ON "Item".id = x.id`
|
) x ON "Item".id = x.id`
|
||||||
}
|
}
|
||||||
|
|
||||||
const LEFT_JOIN_SATS =
|
const LEFT_JOIN_WEIGHTED_SATS =
|
||||||
`LEFT JOIN (${LEFT_JOIN_SATS_SELECT}
|
`LEFT JOIN (${LEFT_JOIN_SATS_SELECT}
|
||||||
FROM "Item" i
|
FROM "Item" i
|
||||||
JOIN "ItemAct" ON i.id = "ItemAct"."itemId"
|
JOIN "ItemAct" ON i.id = "ItemAct"."itemId"
|
||||||
GROUP BY i.id) x ON "Item".id = x.id`
|
GROUP BY i.id) x ON "Item".id = x.id`
|
||||||
|
|
||||||
|
// const LEFT_JOIN_SATS =
|
||||||
|
// `LEFT JOIN (${LEFT_JOIN_SATS_SELECT}
|
||||||
|
// FROM "Item" i
|
||||||
|
// JOIN "ItemAct" ON i.id = "ItemAct"."itemId"
|
||||||
|
// GROUP BY i.id) x ON "Item".id = x.id`
|
||||||
|
|
||||||
/* NOTE: because many items will have the same rank, we need to tie break with a unique field so pagination works */
|
/* NOTE: because many items will have the same rank, we need to tie break with a unique field so pagination works */
|
||||||
function timedOrderBySats (num) {
|
function timedOrderBySats (num) {
|
||||||
return `ORDER BY (GREATEST(x.sats-1, 0)/POWER(EXTRACT(EPOCH FROM ($${num} - "Item".created_at))/3600+2, 1.5) +
|
return `ORDER BY (GREATEST(x.sats-1, 0)/POWER(EXTRACT(EPOCH FROM ($${num} - "Item".created_at))/3600+2, 1.5) +
|
||||||
|
|
|
@ -41,19 +41,33 @@ export default {
|
||||||
|
|
||||||
return me.name?.toUpperCase() === name?.toUpperCase() || !(await models.user.findUnique({ where: { name } }))
|
return me.name?.toUpperCase() === name?.toUpperCase() || !(await models.user.findUnique({ where: { name } }))
|
||||||
},
|
},
|
||||||
topUsers: async (parent, { cursor, within }, { models, me }) => {
|
topUsers: async (parent, { cursor, within, userType }, { models, me }) => {
|
||||||
const decodedCursor = decodeCursor(cursor)
|
const decodedCursor = decodeCursor(cursor)
|
||||||
const users = await models.$queryRaw(`
|
let users
|
||||||
SELECT users.name, users.created_at, sum("ItemAct".sats) as stacked
|
if (userType === 'spent') {
|
||||||
|
users = await models.$queryRaw(`
|
||||||
|
SELECT users.name, users.created_at, sum("ItemAct".sats) as amount
|
||||||
|
FROM "ItemAct"
|
||||||
|
JOIN users on "ItemAct"."userId" = users.id
|
||||||
|
WHERE "ItemAct".created_at <= $1
|
||||||
|
${topClause(within)}
|
||||||
|
GROUP BY users.id, users.name
|
||||||
|
ORDER BY amount DESC NULLS LAST, users.created_at DESC
|
||||||
|
OFFSET $2
|
||||||
|
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
||||||
|
} else {
|
||||||
|
users = await models.$queryRaw(`
|
||||||
|
SELECT users.name, users.created_at, sum("ItemAct".sats) as amount
|
||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" on "ItemAct"."itemId" = "Item".id
|
JOIN "Item" on "ItemAct"."itemId" = "Item".id
|
||||||
JOIN users on "Item"."userId" = users.id
|
JOIN users on "Item"."userId" = users.id
|
||||||
WHERE act <> 'BOOST' AND "ItemAct"."userId" <> users.id AND "ItemAct".created_at <= $1
|
WHERE act <> 'BOOST' AND "ItemAct"."userId" <> users.id AND "ItemAct".created_at <= $1
|
||||||
${topClause(within)}
|
${topClause(within)}
|
||||||
GROUP BY users.id, users.name
|
GROUP BY users.id, users.name
|
||||||
ORDER BY stacked DESC NULLS LAST, users.created_at DESC
|
ORDER BY amount DESC NULLS LAST, users.created_at DESC
|
||||||
OFFSET $2
|
OFFSET $2
|
||||||
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursor: users.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
cursor: users.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
||||||
|
|
|
@ -43,7 +43,9 @@ export default gql`
|
||||||
createdAt: String!
|
createdAt: String!
|
||||||
updatedAt: String!
|
updatedAt: String!
|
||||||
title: String
|
title: String
|
||||||
|
searchTitle: String
|
||||||
url: String
|
url: String
|
||||||
|
searchText: String
|
||||||
text: String
|
text: String
|
||||||
parentId: Int
|
parentId: Int
|
||||||
parent: Item
|
parent: Item
|
||||||
|
|
|
@ -6,7 +6,7 @@ export default gql`
|
||||||
user(name: String!): User
|
user(name: String!): User
|
||||||
users: [User!]
|
users: [User!]
|
||||||
nameAvailable(name: String!): Boolean!
|
nameAvailable(name: String!): Boolean!
|
||||||
topUsers(cursor: String, within: String!): Users
|
topUsers(cursor: String, within: String!, userType: String!): TopUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users {
|
type Users {
|
||||||
|
@ -14,6 +14,17 @@ export default gql`
|
||||||
users: [User!]!
|
users: [User!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TopUsers {
|
||||||
|
cursor: String
|
||||||
|
users: [TopUser!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
type TopUser {
|
||||||
|
name: String!
|
||||||
|
createdAt: String!
|
||||||
|
amount: Int!
|
||||||
|
}
|
||||||
|
|
||||||
extend type Mutation {
|
extend type Mutation {
|
||||||
setName(name: String!): Boolean
|
setName(name: String!): Boolean
|
||||||
setSettings(tipDefault: Int!): Boolean
|
setSettings(tipDefault: Int!): Boolean
|
||||||
|
|
|
@ -165,7 +165,7 @@ export default function Comment ({
|
||||||
: (
|
: (
|
||||||
<div className={styles.text}>
|
<div className={styles.text}>
|
||||||
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>
|
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>
|
||||||
{truncate ? truncateString(item.text) : item.text}
|
{truncate ? truncateString(item.text) : item.searchText || item.text}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -42,9 +42,9 @@ function ItemEmbed ({ item }) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function TopLevelItem ({ item, noReply }) {
|
function TopLevelItem ({ item, noReply, ...props }) {
|
||||||
return (
|
return (
|
||||||
<Item item={item}>
|
<Item item={item} {...props}>
|
||||||
{item.text && <ItemText item={item} />}
|
{item.text && <ItemText item={item} />}
|
||||||
{item.url && <ItemEmbed item={item} />}
|
{item.url && <ItemEmbed item={item} />}
|
||||||
{!noReply && <Reply parentId={item.id} replyOpen />}
|
{!noReply && <Reply parentId={item.id} replyOpen />}
|
||||||
|
@ -53,7 +53,7 @@ function TopLevelItem ({ item, noReply }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemText ({ item }) {
|
function ItemText ({ item }) {
|
||||||
return <Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.text}</Text>
|
return <Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.searchText || item.text}</Text>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ItemFull ({ item, bio, ...props }) {
|
export default function ItemFull ({ item, bio, ...props }) {
|
||||||
|
|
|
@ -6,6 +6,13 @@ import { useEffect, useRef, useState } from 'react'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import { NOFOLLOW_LIMIT } from '../lib/constants'
|
import { NOFOLLOW_LIMIT } from '../lib/constants'
|
||||||
import Pin from '../svgs/pushpin-fill.svg'
|
import Pin from '../svgs/pushpin-fill.svg'
|
||||||
|
import reactStringReplace from 'react-string-replace'
|
||||||
|
|
||||||
|
function SearchTitle ({ title }) {
|
||||||
|
return reactStringReplace(title, /:high\[([^\]]+)\]/g, (match, i) => {
|
||||||
|
return <mark key={`mark-${match}`}>{match}</mark>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default function Item ({ item, rank, children }) {
|
export default function Item ({ item, rank, children }) {
|
||||||
const mine = item.mine
|
const mine = item.mine
|
||||||
|
@ -34,7 +41,9 @@ export default function Item ({ item, rank, children }) {
|
||||||
<div className={styles.hunk}>
|
<div className={styles.hunk}>
|
||||||
<div className={`${styles.main} flex-wrap ${wrap ? 'd-inline' : ''}`}>
|
<div className={`${styles.main} flex-wrap ${wrap ? 'd-inline' : ''}`}>
|
||||||
<Link href={`/items/${item.id}`} passHref>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
<a ref={titleRef} className={`${styles.title} text-reset mr-2`}>{item.title}</a>
|
<a ref={titleRef} className={`${styles.title} text-reset mr-2`}>
|
||||||
|
{item.searchTitle ? <SearchTitle title={item.searchTitle} /> : item.title}
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
{item.url &&
|
{item.url &&
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -36,13 +36,15 @@ export default function Search () {
|
||||||
}}
|
}}
|
||||||
className={`w-auto ${styles.active}`}
|
className={`w-auto ${styles.active}`}
|
||||||
onSubmit={async ({ q }) => {
|
onSubmit={async ({ q }) => {
|
||||||
|
if (q.trim() !== '') {
|
||||||
router.push(`/search?q=${q}`)
|
router.push(`/search?q=${q}`)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
name='q'
|
name='q'
|
||||||
required
|
required
|
||||||
autoFocus
|
autoFocus={showSearch && !atBottom}
|
||||||
groupClassName='mr-3 mb-0 flex-grow-1'
|
groupClassName='mr-3 mb-0 flex-grow-1'
|
||||||
className='w-100'
|
className='w-100'
|
||||||
onChange={async (formik, e) => {
|
onChange={async (formik, e) => {
|
||||||
|
|
|
@ -5,6 +5,25 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
|
||||||
/* Use `…/dist/cjs/…` if you’re not in ESM! */
|
/* Use `…/dist/cjs/…` if you’re not in ESM! */
|
||||||
import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
|
import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
|
||||||
import mention from '../lib/remark-mention'
|
import mention from '../lib/remark-mention'
|
||||||
|
import remarkDirective from 'remark-directive'
|
||||||
|
import { visit } from 'unist-util-visit'
|
||||||
|
|
||||||
|
function myRemarkPlugin () {
|
||||||
|
return (tree) => {
|
||||||
|
visit(tree, (node) => {
|
||||||
|
if (
|
||||||
|
node.type === 'textDirective' ||
|
||||||
|
node.type === 'leafDirective'
|
||||||
|
) {
|
||||||
|
if (node.name !== 'high') return
|
||||||
|
|
||||||
|
const data = node.data || (node.data = {})
|
||||||
|
data.hName = 'mark'
|
||||||
|
data.hProperties = {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function Text ({ nofollow, children }) {
|
export default function Text ({ nofollow, children }) {
|
||||||
return (
|
return (
|
||||||
|
@ -37,7 +56,7 @@ export default function Text ({ nofollow, children }) {
|
||||||
},
|
},
|
||||||
a: ({ node, ...props }) => <a target='_blank' rel={nofollow ? 'nofollow' : null} {...props} />
|
a: ({ node, ...props }) => <a target='_blank' rel={nofollow ? 'nofollow' : null} {...props} />
|
||||||
}}
|
}}
|
||||||
remarkPlugins={[gfm, mention]}
|
remarkPlugins={[gfm, mention, remarkDirective, myRemarkPlugin]}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
|
|
@ -6,20 +6,20 @@ import { useRouter } from 'next/router'
|
||||||
export default function TopHeader ({ cat }) {
|
export default function TopHeader ({ cat }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const within = router.query.within
|
const within = router.query.within
|
||||||
|
const userType = router.query.userType || 'stacked'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar className='pt-0'>
|
<Navbar className='pt-0'>
|
||||||
<Nav
|
<Nav
|
||||||
className={`${styles.navbarNav} justify-content-around`}
|
className={`${styles.navbarNav} justify-content-around`}
|
||||||
activeKey={cat}
|
activeKey={cat.split('/')[0]}
|
||||||
>
|
>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Link href={`/top/posts/${within}`} passHref>
|
<Link href={`/top/posts/${within}`} passHref>
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='posts'
|
eventKey='posts'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'day')}
|
|
||||||
>
|
>
|
||||||
posts
|
posts
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
@ -30,18 +30,16 @@ export default function TopHeader ({ cat }) {
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='comments'
|
eventKey='comments'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'week')}
|
|
||||||
>
|
>
|
||||||
comments
|
comments
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
</Link>
|
</Link>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Link href={`/top/users/${within}`} passHref>
|
<Link href={`/top/users/stacked/${within}`} passHref>
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='users'
|
eventKey='users'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'month')}
|
|
||||||
>
|
>
|
||||||
users
|
users
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
@ -49,6 +47,34 @@ export default function TopHeader ({ cat }) {
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
</Nav>
|
</Nav>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
|
{cat.split('/')[0] === 'users' &&
|
||||||
|
<Navbar className='pt-0'>
|
||||||
|
<Nav
|
||||||
|
className={`${styles.navbarNav} justify-content-around`}
|
||||||
|
activeKey={userType}
|
||||||
|
>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href={`/top/users/stacked/${within}`} passHref>
|
||||||
|
<Nav.Link
|
||||||
|
eventKey='stacked'
|
||||||
|
className={styles.navLink}
|
||||||
|
>
|
||||||
|
stacked
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href={`/top/users/spent/${within}`} passHref>
|
||||||
|
<Nav.Link
|
||||||
|
eventKey='spent'
|
||||||
|
className={styles.navLink}
|
||||||
|
>
|
||||||
|
spent
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
</Nav>
|
||||||
|
</Navbar>}
|
||||||
<Navbar className='pt-0'>
|
<Navbar className='pt-0'>
|
||||||
<Nav
|
<Nav
|
||||||
className={styles.navbarNav}
|
className={styles.navbarNav}
|
||||||
|
@ -59,7 +85,6 @@ export default function TopHeader ({ cat }) {
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='day'
|
eventKey='day'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'day')}
|
|
||||||
>
|
>
|
||||||
day
|
day
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
@ -70,7 +95,6 @@ export default function TopHeader ({ cat }) {
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='week'
|
eventKey='week'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'week')}
|
|
||||||
>
|
>
|
||||||
week
|
week
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
@ -81,7 +105,6 @@ export default function TopHeader ({ cat }) {
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='month'
|
eventKey='month'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'month')}
|
|
||||||
>
|
>
|
||||||
month
|
month
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
@ -92,7 +115,6 @@ export default function TopHeader ({ cat }) {
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='year'
|
eventKey='year'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.setItem('topWithin', 'year')}
|
|
||||||
>
|
>
|
||||||
year
|
year
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
@ -103,7 +125,6 @@ export default function TopHeader ({ cat }) {
|
||||||
<Nav.Link
|
<Nav.Link
|
||||||
eventKey='forever'
|
eventKey='forever'
|
||||||
className={styles.navLink}
|
className={styles.navLink}
|
||||||
onClick={() => localStorage.removeItem('topWithin')}
|
|
||||||
>
|
>
|
||||||
forever
|
forever
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
|
|
|
@ -98,6 +98,8 @@ export const ITEM_SEARCH = gql`
|
||||||
items {
|
items {
|
||||||
...ItemFields
|
...ItemFields
|
||||||
text
|
text
|
||||||
|
searchTitle
|
||||||
|
searchText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,11 @@ export const USER_FIELDS = gql`
|
||||||
}`
|
}`
|
||||||
|
|
||||||
export const TOP_USERS = gql`
|
export const TOP_USERS = gql`
|
||||||
query TopUsers($cursor: String, $within: String!) {
|
query TopUsers($cursor: String, $within: String!, $userType: String!) {
|
||||||
topUsers(cursor: $cursor, within: $within) {
|
topUsers(cursor: $cursor, within: $within, userType: $userType) {
|
||||||
users {
|
users {
|
||||||
name
|
name
|
||||||
stacked
|
amount
|
||||||
}
|
}
|
||||||
cursor
|
cursor
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,14 +42,17 @@
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-longpressable": "^1.1.1",
|
"react-longpressable": "^1.1.1",
|
||||||
"react-markdown": "^6.0.2",
|
"react-markdown": "^6.0.2",
|
||||||
|
"react-string-replace": "^0.4.4",
|
||||||
"react-syntax-highlighter": "^15.4.3",
|
"react-syntax-highlighter": "^15.4.3",
|
||||||
"react-textarea-autosize": "^8.3.3",
|
"react-textarea-autosize": "^8.3.3",
|
||||||
"react-tweet-embed": "^1.3.1",
|
"react-tweet-embed": "^1.3.1",
|
||||||
|
"remark-directive": "^2.0.1",
|
||||||
"remark-gfm": "^1.0.0",
|
"remark-gfm": "^1.0.0",
|
||||||
"remove-markdown": "^0.3.0",
|
"remove-markdown": "^0.3.0",
|
||||||
"sass": "^1.32.8",
|
"sass": "^1.32.8",
|
||||||
"secp256k1": "^4.0.2",
|
"secp256k1": "^4.0.2",
|
||||||
"swr": "^0.5.4",
|
"swr": "^0.5.4",
|
||||||
|
"unist-util-visit": "^4.1.0",
|
||||||
"use-dark-mode": "^2.3.1",
|
"use-dark-mode": "^2.3.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"webln": "^0.2.2",
|
"webln": "^0.2.2",
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
import Layout from '../../../components/layout'
|
import Layout from '../../../../components/layout'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { getGetServerSideProps } from '../../../api/ssrApollo'
|
import { getGetServerSideProps } from '../../../../api/ssrApollo'
|
||||||
import TopHeader from '../../../components/top-header'
|
import TopHeader from '../../../../components/top-header'
|
||||||
import { TOP_USERS } from '../../../fragments/users'
|
import { TOP_USERS } from '../../../../fragments/users'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import MoreFooter from '../../../components/more-footer'
|
import MoreFooter from '../../../../components/more-footer'
|
||||||
|
|
||||||
export const getServerSideProps = getGetServerSideProps(TOP_USERS)
|
export const getServerSideProps = getGetServerSideProps(TOP_USERS)
|
||||||
|
|
||||||
export default function Index ({ data: { topUsers: { users, cursor } } }) {
|
export default function Index ({ data: { topUsers: { users, cursor } } }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const userType = router.query.userType
|
||||||
|
|
||||||
const { data, fetchMore } = useQuery(TOP_USERS, {
|
const { data, fetchMore } = useQuery(TOP_USERS, {
|
||||||
variables: { within: router.query?.within }
|
variables: { within: router.query?.within, userType: router.query?.userType }
|
||||||
})
|
})
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
|
@ -22,12 +23,12 @@ export default function Index ({ data: { topUsers: { users, cursor } } }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<TopHeader cat='users' />
|
<TopHeader cat={'users/' + userType} />
|
||||||
{users.map(user => (
|
{users.map(user => (
|
||||||
<Link href={`/${user.name}`} key={user.name}>
|
<Link href={`/${user.name}`} key={user.name}>
|
||||||
<div className='d-flex align-items-center pointer'>
|
<div className='d-flex align-items-center pointer'>
|
||||||
<h3 className='mb-0'>@{user.name}</h3>
|
<h3 className='mb-0'>@{user.name}</h3>
|
||||||
<h2 className='ml-2 mb-0'><small className='text-success'>{user.stacked} stacked</small></h2>
|
<h2 className='ml-2 mb-0'><small className='text-success'>{user.amount} {userType}</small></h2>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
|
@ -270,7 +270,7 @@ export function LnAddrWithdrawal () {
|
||||||
schema={LnAddrSchema}
|
schema={LnAddrSchema}
|
||||||
initialError={error ? error.toString() : undefined}
|
initialError={error ? error.toString() : undefined}
|
||||||
onSubmit={async ({ addr, amount, maxFee }) => {
|
onSubmit={async ({ addr, amount, maxFee }) => {
|
||||||
const { data } = await sendToLnAddr({ variables: { addr, amount: Number(amount), maxFee } })
|
const { data } = await sendToLnAddr({ variables: { addr, amount: Number(amount), maxFee: Number(maxFee) } })
|
||||||
router.push(`/withdrawals/${data.sendToLnAddr.id}`)
|
router.push(`/withdrawals/${data.sendToLnAddr.id}`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
18
pages/wot.js
18
pages/wot.js
|
@ -1,18 +0,0 @@
|
||||||
import Layout from '../components/layout'
|
|
||||||
import Items from '../components/items'
|
|
||||||
import { getGetServerSideProps } from '../api/ssrApollo'
|
|
||||||
import { MORE_ITEMS } from '../fragments/items'
|
|
||||||
|
|
||||||
const variables = { sort: 'wot' }
|
|
||||||
export const getServerSideProps = getGetServerSideProps(MORE_ITEMS, variables)
|
|
||||||
|
|
||||||
export default function Index ({ data: { moreItems: { items, pins, cursor } } }) {
|
|
||||||
return (
|
|
||||||
<Layout>
|
|
||||||
<Items
|
|
||||||
items={items} pins={pins} cursor={cursor}
|
|
||||||
variables={variables} rank
|
|
||||||
/>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ const Pageres = require('pageres')
|
||||||
|
|
||||||
async function captureUrl () {
|
async function captureUrl () {
|
||||||
try {
|
try {
|
||||||
const streams = await new Pageres({ crop: true, scale: 2, timeout: 10, launchOptions: { args: ['--single-process'] } })
|
const streams = await new Pageres({ crop: true, delay: 1, scale: 2, timeout: 10, launchOptions: { args: ['--single-process'] } })
|
||||||
.src(process.argv[2], ['600x315'])
|
.src(process.argv[2], ['600x315'])
|
||||||
.run()
|
.run()
|
||||||
process.stdout.write(streams[0], () => process.exit(0))
|
process.stdout.write(streams[0], () => process.exit(0))
|
||||||
|
|
|
@ -65,6 +65,11 @@ $tooltip-bg: #5c8001;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: var(--primary);
|
||||||
|
padding: 0 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.table-sm th, .table-sm td {
|
.table-sm th, .table-sm td {
|
||||||
line-height: 1.2rem;
|
line-height: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue