Collection editor: Format topic as hashtag (#38153)

This commit is contained in:
diondiondion authored and GitHub committed 2026-03-11 17:04:37 +00:00
1 parent 3091e2e525
commit 3ef7d2835a
4 files changed
+81 -17

No files matched your search

@@ -0,0 +1,28 @@
import { inputToHashtag } from './hashtags';
describe('inputToHashtag', () => {
test.concurrent.each([
['', ''],
// Prepend or keep hashtag
['mastodon', '#mastodon'],
['#mastodon', '#mastodon'],
// Preserve trailing whitespace
['mastodon ', '#mastodon '],
[' ', '# '],
// Collapse whitespace & capitalise first character
['cats of mastodon', '#catsOfMastodon'],
['x y z', '#xYZ'],
[' mastodon', '#mastodon'],
// Preserve initial casing
['Log in', '#LogIn'],
['#NaturePhotography', '#NaturePhotography'],
// Normalise hash symbol variant
['#nature', '#nature'],
['#Nature Photography', '#NaturePhotography'],
// Allow special characters
['hello-world', '#hello-world'],
['hello,world', '#hello,world'],
])('for input "%s", return "%s"', (input, expected) => {
expect(inputToHashtag(input)).toBe(expected);
});
});
+32
View File
@@ -27,3 +27,35 @@ const buildHashtagRegex = () => {
export const HASHTAG_PATTERN_REGEX = buildHashtagPatternRegex();
export const HASHTAG_REGEX = buildHashtagRegex();
/**
* Formats an input string as a hashtag:
* - Prepends `#` unless present
* - Strips spaces (except at the end, to allow typing it)
* - Capitalises first character after stripped space
*/
export const inputToHashtag = (input: string): string => {
if (!input) {
return '';
}
const trailingSpace = /\s+$/.exec(input)?.[0] ?? '';
const trimmedInput = input.trimEnd();
const withoutHash =
trimmedInput.startsWith('#') || trimmedInput.startsWith('#')
? trimmedInput.slice(1)
: trimmedInput;
// Split by space, filter empty strings, and capitalise the start of each word but the first
const words = withoutHash
.split(/\s+/)
.filter((word) => word.length > 0)
.map((word, index) =>
index === 0
? word
: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
);
return `#${words.join('')}${trailingSpace}`;
};