Skip to content

Add silent message badge and polls - #86

Open
Antouto wants to merge 6 commits into
discohook:mainfrom
Antouto:main
Open

Antouto wants to merge 6 commits into
discohook:mainfrom
Antouto:main

Conversation

@Antouto

@Antouto Antouto commented Apr 19, 2026

Copy link
Copy Markdown

Before:
Screenshot 2026-04-19 at 17 41 27

After:
Screenshot 2026-04-19 at 17 41 58

@Antouto Antouto changed the title Add silent message badge Add silent message badge and polls Apr 20, 2026
@Antouto

Antouto commented Apr 20, 2026

Copy link
Copy Markdown
Author

Adds polls to the editor and preview 😁
I'll leave flows, restore command, share links, backups, code gen etc. up to you.

@Antouto

Antouto commented Apr 20, 2026

Copy link
Copy Markdown
Author
Screenshot 2026-04-20 at 21 44 41

@shayypy

shayypy commented Apr 22, 2026 •

Copy link
Copy Markdown
Member

Don't have time to review yet but would it be possible for you to split polls into a separate PR since they require extra work?
Looks great so far though!

@shayypy shayypy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason my git client is checking out 84 when I try to check out 86, so I can't actually make any changes myself right now, but these are the things I noticed while looking this over on GH

Comment on lines +59 to +62
<span className="truncate">
{`Answer ${index + 1}`}
{previewText ? ` - ${previewText}` : ""}
</span>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be localized: react, i18n

Comment on lines +190 to +193
<p className="truncate">
Poll
{previewText ? ` - ${previewText}` : ""}
</p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also be localized, see comment on answer component

<div className="space-y-2">
{disabled && (
<InfoBox severity="blue" icon="Info">
Polls cannot be edited for existing messages.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Polls cannot be edited for existing messages.
{t("pollsImmutable")}

Add to i18n

Comment on lines +213 to +217
{disabled && (
<InfoBox severity="blue" icon="Info">
Polls cannot be edited for existing messages.
</InfoBox>
)}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{disabled && (
<InfoBox severity="blue" icon="Info">
Polls cannot be edited for existing messages.
</InfoBox>
)}
{disabled ? (
<InfoBox severity="blue" icon="Info">
Polls cannot be edited for existing messages.
</InfoBox>
) : null}

I prefer to use a ternary operator these days but it's not a huge deal since disabled is a bool

Comment on lines +246 to +248
const answers = [...poll.answers];
answers.splice(index, 1, updatedAnswer);
updatePoll({ ...poll, answers });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if the double spread is necessary. You aren't duplicating poll (otherwise you'd use structuredClone) so I think just the one spread in updatePoll would be fine, splicing the original array to update the answer, unless I do something else in another example. Ditto for the other callbacks here of course

return (
<img
src={cdn.emoji(emoji.id, emoji.animated ? "gif" : "webp")}
className="h-[22px] w-[22px] shrink-0 object-contain"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
className="h-[22px] w-[22px] shrink-0 object-contain"
className="size-[22px] shrink-0 object-contain"

return (
<Twemoji
emoji={emoji.name}
className="h-[22px] w-[22px] shrink-0 align-middle"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
className="h-[22px] w-[22px] shrink-0 align-middle"
className="size-[22px] shrink-0 align-middle"

{poll.question.text}
</h4>
<div className="mt-1 text-muted dark:text-muted-dark text-[14px]">
Select one answer

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Select one answer
{t("selectOneAnswer")}

Comment on lines +35 to +36
poll: NonNullable<QueryData["messages"][number]["data"]["poll"]>;
}> = ({ poll }) => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
poll: NonNullable<QueryData["messages"][number]["data"]["poll"]>;
}> = ({ poll }) => {
t: TFunction;
poll: NonNullable<QueryData["messages"][number]["data"]["poll"]>;
}> = ({ t, poll }) => {

It would probably be fine to call useTranslation in this component but I think I usually simply pass it to preview components like this

Comment on lines +82 to +94
<div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer">
0 votes
</div>
<div className="before:mx-2 before:text-[20px] before:leading-none before:content-['\2219'] text-muted dark:text-muted-dark" />
<div className="text-muted dark:text-muted-dark">
{poll.duration ?? 24}h left
</div>
</div>
<div className="flex items-center gap-4">
<div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer text-[14px]">
Show results
</div>
<Button disabled>Vote</Button>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer">
0 votes
</div>
<div className="before:mx-2 before:text-[20px] before:leading-none before:content-['\2219'] text-muted dark:text-muted-dark" />
<div className="text-muted dark:text-muted-dark">
{poll.duration ?? 24}h left
</div>
</div>
<div className="flex items-center gap-4">
<div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer text-[14px]">
Show results
</div>
<Button disabled>Vote</Button>
<div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer">
{t("nVotes", { count: 0 })}
</div>
<div className="before:mx-2 before:text-[20px] before:leading-none before:content-['\2219'] text-muted dark:text-muted-dark" />
<div className="text-muted dark:text-muted-dark">
{t("pollDurationLeft", { values: { hours: poll.duration ?? 24 } })}
</div>
</div>
<div className="flex items-center gap-4">
<div className="text-[#28282d] dark:text-[#fbfbfb] hover:underline cursor-pointer text-[14px]">
{t("showResults")}
</div>
<Button disabled>{t("vote")}</Button>

Polls in Discord actually change the unit based on the amount of time remaining and do not only show hours. I'd like to do that here as well, a la timestamp.relative.*

The localization w/ count for a constant 0 votes might seem weird but I'd rather it be more "realistic" so to speak. Also, I may implement a feature to fetch vote data for the preview, so we want a real localized count there.

@shayypy

shayypy commented Apr 24, 2026

Copy link
Copy Markdown
Member

Another thing, don't bother with splitting polls into a new PR, I'll just merge this and then mark it as an experiment so I can keep working on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants