Files
5chan/src/lib/comment-flag-selection.ts
T
Tommaso CasaburiandGitHub 829b672053 fix(embed): restore youtube thumbnails and file-row labels (#1148)
* fix(comment-content): render reason text as comment content

* fix(post-form): use native browser styling for flash tag select

Exclude the flash tag dropdown from themed post-form select styling so it
renders with the browser's default select appearance, matching the flag selector.

* fix(p2p-stats): show peer flags for DNS6 relay hostnames

Extract embedded IPv6 addresses from dns6 multiaddrs so geo lookup and country flags work for relay peers that publish IPv6 via DNS hostnames.

* fix(flags): hide geolocation-only selectors on /int/ and /sp/

Country-only boards auto-publish geographic location flags without
showing a flag dropdown, matching existing /bant/ behavior.

* fix(embed): restore youtube thumbnails and file-row labels

Restore thumbnail-first previews for YouTube embeds in post media and markdown hover.
Desktop posts show File with the thumbnail image URL and a youtube video type label.

* fix(embed): address youtube thumbnail review feedback

Translate the youtube video label, handle mobile/music YouTube hosts as standard YouTube URLs, keep affected mocks current, and cap default Vitest workers to reduce local CPU spikes.
2026-06-01 12:57:17 +07:00

146 lines
4.3 KiB
TypeScript

import { getBoardFlagDefinition, getBoardFlagDefinitions, type BoardFlagKind } from './board-flags';
import type { DirectoryCommunity } from './utils/directory-list-utils';
const GEOGRAPHIC_LOCATION_FLAG_VALUE = 'country:auto';
const NO_FLAG_VALUE = 'none';
const FLAG_CHALLENGE_ANSWER_PREFIX = 'bitsocial-flags:5chan:';
export interface CommentFlagSelectOption {
value: string;
label: string;
}
export interface CommentFlagRequest {
type: 'country' | BoardFlagKind;
code: string;
text: string;
}
interface CommentFlagChallengeRequest {
challengeAnswers: string[];
}
export interface CommentFlagPublishOptions {
challengeRequest: CommentFlagChallengeRequest | undefined;
flairs: CommentFlagRequest[] | undefined;
}
export type CommentFlagDirectory = Partial<Pick<DirectoryCommunity, 'directoryCode' | 'features' | 'title'>>;
const GEOGRAPHIC_LOCATION_OPTION: CommentFlagSelectOption = {
value: GEOGRAPHIC_LOCATION_FLAG_VALUE,
label: 'Geographic Location',
};
const NO_FLAG_OPTION: CommentFlagSelectOption = {
value: NO_FLAG_VALUE,
label: 'None',
};
/** Boards that always publish geographic location without showing a flag selector. */
const AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES = new Set(['bant', 'int', 'sp']);
const getDirectoryCode = (directory: Pick<DirectoryCommunity, 'directoryCode' | 'title'> | undefined): string | undefined => {
const directoryCode = directory?.directoryCode?.trim().toLowerCase();
return directoryCode || directory?.title?.match(/^\/([^/]+)\//)?.[1]?.toLowerCase();
};
export const hasCommentFlagsForDirectory = (directory: CommentFlagDirectory | undefined): boolean => {
return directory?.features?.hasFlags === true;
};
const getBoardFlagOptions = (kind: BoardFlagKind): CommentFlagSelectOption[] =>
getBoardFlagDefinitions(kind).map((flag) => ({
value: `${flag.kind}:${flag.code}`,
label: flag.label,
}));
export const getCommentFlagOptionsForDirectory = (directory: CommentFlagDirectory | undefined): CommentFlagSelectOption[] => {
if (!hasCommentFlagsForDirectory(directory)) {
return [];
}
const directoryCode = getDirectoryCode(directory);
if (directoryCode && AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES.has(directoryCode)) {
return [];
}
if (directoryCode === 'mlp') {
return [NO_FLAG_OPTION, ...getBoardFlagOptions('pony')];
}
if (directoryCode === 'pol') {
return [GEOGRAPHIC_LOCATION_OPTION, ...getBoardFlagOptions('pol')];
}
return [GEOGRAPHIC_LOCATION_OPTION];
};
export const getCommentFlagPublishOptionsForDirectory = (directory: CommentFlagDirectory | undefined, selectedValue?: string): CommentFlagPublishOptions => {
if (!hasCommentFlagsForDirectory(directory)) {
return {
challengeRequest: undefined,
flairs: undefined,
};
}
const directoryCode = getDirectoryCode(directory);
if (directoryCode && AUTO_GEOGRAPHIC_FLAG_DIRECTORY_CODES.has(directoryCode)) {
return getCommentFlagPublishOptionsFromSelection(GEOGRAPHIC_LOCATION_FLAG_VALUE);
}
const flagOptions = getCommentFlagOptionsForDirectory(directory);
if (flagOptions.length === 0) {
return {
challengeRequest: undefined,
flairs: undefined,
};
}
return getCommentFlagPublishOptionsFromSelection(selectedValue ?? flagOptions[0]?.value);
};
export const getCommentFlagRequestFromSelection = (value: string | undefined): CommentFlagRequest | undefined => {
if (!value || value === NO_FLAG_VALUE) {
return undefined;
}
if (value === GEOGRAPHIC_LOCATION_FLAG_VALUE) {
return {
type: 'country',
code: 'auto',
text: 'flag:country:auto',
};
}
const match = value.match(/^(pol|pony):([A-Z0-9]+)$/);
if (!match) {
return undefined;
}
const [, kind, code] = match;
const flag = getBoardFlagDefinition(kind, code);
return flag
? {
type: flag.kind,
code: flag.code,
text: `flag:${flag.kind}:${flag.code}`,
}
: undefined;
};
export const getCommentFlagPublishOptionsFromSelection = (value: string | undefined): CommentFlagPublishOptions => {
const flag = getCommentFlagRequestFromSelection(value);
return flag
? {
challengeRequest: {
challengeAnswers: [`${FLAG_CHALLENGE_ANSWER_PREFIX}${flag.text}`],
},
flairs: [flag],
}
: {
challengeRequest: undefined,
flairs: undefined,
};
};