soxa 0e842e9915
live comments: auto show new comments (#2355)
* enhance: FaviconProvider, keep track of new comment IDs to change favicon, remove new comment IDs per outline removal

* don't track oneself comments

* enhance: auto-show new comments, idempotency by ignoring already injected comments, preserveScroll utility

* fadeIn animation on comment injection; cleanup: remove unused counts and thread handling; non-critical fix: always give rootLastCommentAt a value

* reliably preserve scroll position by tracking a reference found at the center of the viewport; cleanup: add more comments, add cleanup function

* mitigate fractional scrolling subtle layout shifts by rounding the new reference element position

* enhanced outlining system, favicon context keeps track of new comments presence

- de-outlining now happens only for outlined comments
- enhanced outlining: add outline only if isNewComment
- de-outlining will remove the new comments favicon
- on unmount remove the new comments favicon

* remove the new comments favicon on new comments injection

* track only deduplicated new comments

* fix typo

* clearer unsetOutline conditions, fix typo in live comments hook

* backport: remove the injectedComment class from injected comments after animation ends

* set the new comments favicon on any new outlined comment

* enhance: directly inject new comments; cleanup: dismantle ShowNewComments, remove newComments field

* tweaks: slower injection animation, clear favicon on Comment section unmount

* change nDirectComments bug strategy to avoiding updates on comment edit

* cleanup: better naming, re-instate injected comments outline

* injection: major cache utilities refactor, don't preserve scroll if no comments have been injected

- don't preserve scroll if after deduplication we don't inject any comments

- use manual read/write cache updates to control the flow
-- allows to check if we are really injecting or not

- reduce polling to 5 seconds instead of 10

- light cleanup
-- removed update cache functions
-- added 'injected' to typeDefs (gql consistency)

* cleanup: detailed comments, refactor, remove clutter

Refactor:
+ clearer variables
+ depth calculation utility function
+ use destructured Apollo cache
+ extract item object from item query
+ skip ignored comment instead of ending the loop

CSS:
+ from-to fadeIn animation keyframes
- floatingComments unused class

Favicon:
+ provider exported by default

* fix wrong merge

* split: remove favicon context

* split: remove favicon pngs

* regression: revert to updateQuery for multiple comment fragments handling

* reverse multiple reads for deduplication on comment injection

* fix regression on apollo manipulations via fn; cleanup: remove wrong deps from outlining
2025-08-08 10:04:54 -05:00

182 lines
4.5 KiB
JavaScript

import { gql } from 'graphql-tag'
export default gql`
extend type Query {
items(sub: String, sort: String, type: String, cursor: String, name: String, when: String, from: String, to: String, by: String, limit: Limit): Items
item(id: ID!): Item
pageTitleAndUnshorted(url: String!): TitleUnshorted
dupes(url: String!): [Item!]
related(cursor: String, title: String, id: ID, minMatch: String, limit: Limit): Items
search(q: String, sub: String, cursor: String, what: String, sort: String, when: String, from: String, to: String): Items
auctionPosition(sub: String, id: ID, boost: Int): Int!
boostPosition(sub: String, id: ID, boost: Int): BoostPositions!
itemRepetition(parentId: ID): Int!
newComments(rootId: ID, after: Date): Comments!
}
type BoostPositions {
home: Boolean!
sub: Boolean!
homeMaxBoost: Int!
subMaxBoost: Int!
}
type TitleUnshorted {
title: String
unshorted: String
}
type ItemActResult {
id: ID!
sats: Int!
path: String
act: String!
}
type ItemAct {
id: ID!
act: String!
invoice: Invoice
}
extend type Mutation {
bookmarkItem(id: ID): Item
pinItem(id: ID): Item
subscribeItem(id: ID): Item
deleteItem(id: ID): Item
upsertLink(
id: ID, sub: String, title: String!, url: String!, text: String, boost: Int, forward: [ItemForwardInput],
hash: String, hmac: String): ItemPaidAction!
upsertDiscussion(
id: ID, sub: String, title: String!, text: String, boost: Int, forward: [ItemForwardInput],
hash: String, hmac: String): ItemPaidAction!
upsertBounty(
id: ID, sub: String, title: String!, text: String, bounty: Int, boost: Int, forward: [ItemForwardInput],
hash: String, hmac: String): ItemPaidAction!
upsertJob(
id: ID, sub: String!, title: String!, company: String!, location: String, remote: Boolean,
text: String!, url: String!, boost: Int, status: String, logo: Int): ItemPaidAction!
upsertPoll(
id: ID, sub: String, title: String!, text: String, options: [String!]!, boost: Int, forward: [ItemForwardInput], pollExpiresAt: Date,
randPollOptions: Boolean, hash: String, hmac: String): ItemPaidAction!
updateNoteId(id: ID!, noteId: String!): Item!
upsertComment(id: ID, text: String!, parentId: ID, boost: Int, hash: String, hmac: String): ItemPaidAction!
act(id: ID!, sats: Int, act: String, hasSendWallet: Boolean): ItemActPaidAction!
pollVote(id: ID!): PollVotePaidAction!
toggleOutlaw(id: ID!): Item!
}
type PollVoteResult {
id: ID!
}
type PollOption {
id: ID,
option: String!
count: Int!
}
type Poll {
meVoted: Boolean!
meInvoiceId: Int
meInvoiceActionState: InvoiceActionState
count: Int!
options: [PollOption!]!
randPollOptions: Boolean
}
type Items {
cursor: String
items: [Item!]!
pins: [Item!]
ad: Item
}
type Comments {
cursor: String
comments: [Item!]!
}
enum InvoiceActionState {
PENDING
PENDING_HELD
HELD
PAID
FAILED
}
type Item {
id: ID!
createdAt: Date!
updatedAt: Date!
invoicePaidAt: Date
deletedAt: Date
deleteScheduledAt: Date
reminderScheduledAt: Date
title: String
searchTitle: String
url: String
searchText: String
text: String
parentId: Int
parent: Item
root: Item
user: User!
userId: Int!
depth: Int
mine: Boolean!
boost: Int!
bounty: Int
bountyPaidTo: [Int]
noteId: String
sats: Int!
credits: Int!
commentSats: Int!
commentCredits: Int!
lastCommentAt: Date
upvotes: Int!
meSats: Int!
meCredits: Int!
meDontLikeSats: Int!
meBookmark: Boolean!
meSubscription: Boolean!
meForward: Boolean
outlawed: Boolean!
freebie: Boolean!
freedFreebie: Boolean!
bio: Boolean!
paidImgLink: Boolean
ncomments: Int!
nDirectComments: Int!
comments(sort: String, cursor: String): Comments!
injected: Boolean!
path: String
position: Int
prior: Int
isJob: Boolean!
pollCost: Int
poll: Poll
pollExpiresAt: Date
company: String
location: String
remote: Boolean
sub: Sub
subName: String
status: String!
uploadId: Int
otsHash: String
parentOtsHash: String
forwards: [ItemForward]
imgproxyUrls: JSONObject
rel: String
apiKey: Boolean
invoice: Invoice
cost: Int!
}
input ItemForwardInput {
nym: String!
pct: Int!
}
`