Repository navigation
feat: add hashtags - #1059
Closed
chrismessina wants to merge 6 commits into
Closed
feat: add hashtags#1059chrismessina wants to merge 6 commits into
chrismessina wants to merge 6 commits into
Conversation
A hex color written like a hashtag, such as #ff8a4c or #fff, shows with a small swatch of the color. It needs at least one letter, so dev-null-sh#123 stays an issue reference, and colors in code are left alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hashtags follow Bluesky's rule. They are stored on commits for suggestions and the data export, linked on the web, suggested in the commit, reply and quote composers, and sent as positions in the signed API. Hex colors render as swatches. A link or mention never starts inside a hashtag, so "#asp.net" and "#release:@alice" are hashtags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Accepting a suggestion replaced only what was before the caret, so picking #node.js inside "#n|ode.js" gave "#node.js ode.js". It now replaces the whole word, keeps the case of what was already written, and adds no space before punctuation. Hashtags are suggested while typing one, not when the caret moves into one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A completed mention stays apart from a mention right after it, and a hashtag stops before code. At the length limit the caret lands right after the completion. Hashtag suggestions open after an emoji shortcode is typed, and stay closed when the caret only moves back to where typing left it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Changing the selection and collapsing it again no longer reopens hashtag suggestions. After an emoji shortcode is replaced, suggestions open once the caret is back where typing left it, even if the browser reported the caret elsewhere in between. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chrismessina
force-pushed
the
feat/hashtags
branch
from
October 23, 2026 20:15
c707d22 to
5f996f9
Compare
#000 and #000000 are black, and #333333 is gray, but they showed as plain text because a color needed a letter. Issue numbers never start with a zero and aren't 6 or 8 digits long, so those count as colors now, while dev-null-sh#123 and dev-null-sh#333 still stay plain. The pattern also spells its zero-width characters as escapes instead of the invisible characters themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
|
Note This message is generated by an AI agent on behalf of @xHeaven. It may contain errors—verify important details. Closing this in line with Brent’s decision on #9:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds on #1064 (hex color swatches). Until that merges, this diff includes its commit,
feat: show hex colors as swatches.There's no way to tag a commit with a topic, so the only way to find posts about, say, PHP is the meaning-based search. This adds
#hashtags:#phpin a commit is a link to a search for it.#ff8a4cor#fffis never a tag; feat: show hex colors as swatches #1064 draws it with a swatch.#in the commit, reply, or quote composer suggests up to six hashtags. Your own come first (most used, then most recent), then tags from the last 30 days ranked by how many people used them, then alphabetically.The parsing rule is Bluesky's
TAG_REGEX(atprotorich-text/util.ts), ported rather than imported because the server needs it in PHP.#node.js,#.net, and#c++are tags, trailing punctuation isn't part of them, and#123stays an issue reference because a tag needs at least one character that isn't a digit or punctuation. Changes from Bluesky:>that starts a quoted line (>#php), where Bluesky needs whitespace.Changes
App\Services\Hashtagsandresources/js/lib/hashtags.tshold the same rule, kept in sync likeMentions. PHP spells out the whitespace JavaScript's\smatches, so both sides find the same tags.commits.hashtags(jsonb, hidden), written byCreateCommitfrom the body as kept (after emoji shortcodes) and byCreateWorldReply. It's nulled with the body byDeleteCommitContentandDeleteUser, and included in the data export. Answers to the data guideline's questions:CommitResource(not tombstones) and the draft preview addhashtagspositions ({tag, offset, length}, code-point offsets including the#, likementions), so the mobile app can link tags without its own parser.GET search/hashtags(HashtagSuggestionController→ListHashtagSuggestionsRequest→HashtagSuggestionsQuery). It reads only commits the user may see (approved ones, plus their own not yet approved), skips muted people and blocks in either direction, and shares thepeoplerate limit.#where a tag could start (at the start, after whitespace or after>), up to a backtick. So#asp.netand#docs:example.comaren't links and#@aliceand#release:@alicenotify nobody, while[#12](https://…),C#:@aliceand a#in code don't block anything. That's one lookbehind on the existing patterns (Hashtags::WordSoFar, and its copy inmentions.tsandurls.ts), so mention notifications and positions, link cards, the 23-character link count, URL shortening and the composer all agree without tracking where tags are.CreateCommitnow finds mentions and the link card in the body after emoji shortcodes are replaced, as it already did for hashtags. Bluesky avoids the overlap by starting mentions and links only after whitespace or(, and Mastodon by not allowing punctuation in tags; adopting Bluesky's start rule would also stop linking“https://…”, which this app tests for. It stays a little broader than the tag rule: aftera>#x:or in a#word longer than a tag (65 to 255 characters), a mention or link is blocked too.LinkifiedTextlinks tags and keeps them whole, in a step before feat: show hex colors as swatches #1064's colors.@ta|yotwellused to become@taylorotwell yotwell.#hashtags(it isn't checked afterward), andKNOWLEDGE_BASE.mdhas a Hashtags section.Decision for review: trending tags (not in this PR) are planned to count distinct authors across everyone, ignoring each viewer's mutes and blocks, so one cached list serves everyone. That's an exception to
PRODUCT.md's "mutes and blocks filter everywhere". @nunomaduro, overrule this if it shouldn't be.Validation
Local, macOS, PHP 8.5.12, PostgreSQL 18 with pgvector:
pest --parallel --ci: 4,102 passed (onproductionatbb1acc1plus feat: show hex colors as swatches #1064).bun run test:unit: 137 passed.vp test run: all 806 tests passed (422 + 384 across its two projects). It can't load the 35node:testfiles:bun run test:unitruns the 28.tsones, and the 7.tsxones run nowhere, as onproduction.pint --test,rector --dry-run,vp fmt --check,vp lint, andtsc(app and tests): pass.vp lintreports warnings, all from lines this branch doesn't change. Type coverage: 100%.phpstan: 2 errors, both inEmbedKnowledgeBaseCommand.php, which this branch doesn't change. They're the same onproduction.Visual evidence
"Before" is a commit on the live site (base code) and "after" is the same kind of text on this branch, at 1440×900, 1366×650, and 390×844, light and dark.
Layout shift, measured with
PerformanceObserver(layout-shift):#, narrowing, EnterIn every run, a bare
#suggested#laraveland#node.js,#nonarrowed to#node.js, and Enter inserted#node.js.Device verification
macOS 27.0.1, Chrome 156.0.8078.48 driven by Playwright with mobile emulation (390×844, touch). Typing, the popover, and Enter worked; scrolling, client-side navigation, and fresh reloads weren't exercised separately. No hardware or simulator was used, so the on-screen keyboard and safe areas aren't verified. The suggestion popover is the same component mention suggestions already use on mobile.
Independent review
gpt-6.1-sol, high effort), read-only, source and diff only.96a0b8de9566acfa3a819545df0d94a1be6b68c7(feat: show hex colors as swatches #1064's head) →5f996f9a5516868c694757ef423bdad8527e6434. feat: show hex colors as swatches #1064 was reviewed separately (CODE: PASS).a86340d, the same digit-only color change as feat: show hex colors as swatches #1064's, cherry-picked: reviewed on feat: show hex colors as swatches #1064 (CODE: PASS). It doesn't touch hashtags, since a digit-only word is never a tag.Limitations
#rfinds nothing. Exact tag search is the next step if hashtags are wanted.İgrows past 64 characters when lowercased, so suggesting it inserts a tag that won't link.#a`b:@alice) still lets the mention after the backtick through.a>#x:, or inside a#word of 65 to 255 characters, a link or mention is blocked too.