Merge branch 'codex/fix/tor-flag-tooltip'

This commit is contained in:
Tommaso Casaburi
2026-06-04 17:19:07 +07:00
38 changed files with 108 additions and 52 deletions
+21 -15
View File
@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { getCommentFlagFlairs, getAuthorFlagViewModels } from '../lib/comment-flags';
import styles from '../views/post/post.module.css';
@@ -11,6 +12,8 @@ const getBackgroundPosition = (x: number, y: number) => `${x === 0 ? 0 : -x}px $
const transparentPixelSrc = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="1" height="1"%3E%3C/svg%3E';
const PostAuthorFlags = ({ author, comment, enabled }: PostAuthorFlagsProps) => {
const { t } = useTranslation();
if (!enabled) return null;
const flags = getAuthorFlagViewModels(getCommentFlagFlairs(comment, author));
@@ -18,21 +21,24 @@ const PostAuthorFlags = ({ author, comment, enabled }: PostAuthorFlagsProps) =>
return (
<span className={styles.authorFlags}>
{flags.map((flag) => (
<img
key={flag.key}
alt={flag.label}
className={styles.authorFlag}
src={transparentPixelSrc}
style={{
backgroundImage: `url("${flag.spritePath}")`,
backgroundPosition: getBackgroundPosition(flag.x, flag.y),
width: flag.width,
height: flag.height,
}}
title={flag.label}
/>
))}
{flags.map((flag) => {
const label = flag.labelKey ? t(flag.labelKey, flag.label) : flag.label;
return (
<img
key={flag.key}
alt={label}
className={styles.authorFlag}
src={transparentPixelSrc}
style={{
backgroundImage: `url("${flag.spritePath}")`,
backgroundPosition: getBackgroundPosition(flag.x, flag.y),
width: flag.width,
height: flag.height,
}}
title={label}
/>
);
})}
</span>
);
};
+11 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { getCommentFlagFlairs, getAuthorFlagFlairs, getAuthorFlagViewModels } from '../comment-flags';
import { getCommentFlagFlairs, getAuthorFlagFlairs, getAuthorFlagViewModels, TOR_AUTHOR_FLAG_LABEL_KEY } from '../comment-flags';
describe('comment-flags', () => {
it('parses the pkc-js challenge flair example for country flags', () => {
@@ -25,6 +25,16 @@ describe('comment-flags', () => {
expect(flags[2]).toMatchObject({ label: 'Applejack', x: 80, y: 0 });
});
it('labels the xx country flag as Tor traffic', () => {
const [flag] = getAuthorFlagViewModels([{ text: 'flag:country:xx' }], 1000);
expect(flag).toMatchObject({
key: 'country:xx',
label: 'This user is on Tor',
labelKey: TOR_AUTHOR_FLAG_LABEL_KEY,
});
});
it('normalizes text flag kinds before parsing', () => {
const flags = getAuthorFlagViewModels([{ text: 'FLAG:COUNTRY:DE' }, { text: 'POL:AC' }, { text: 'flag:MLP:AJ' }], 1000);
+6 -1
View File
@@ -2,6 +2,9 @@ import { COUNTRY_FLAG_HEIGHT, COUNTRY_FLAG_WIDTH, getCountryFlagPosition, getCou
import { getBoardFlagDefinition, normalizeBoardFlagKind, type BoardFlagKind } from './board-flags';
const COUNTRY_FLAG_SPRITE_PATH = 'assets/icons/flags-1.png';
const TOR_COUNTRY_CODE = 'xx';
const TOR_AUTHOR_FLAG_LABEL = 'This user is on Tor';
export const TOR_AUTHOR_FLAG_LABEL_KEY = 'tor_author_flag_label';
const FLAG_TEXT_PATTERN = /^flag:([a-z-]+):([a-z0-9-]+)$/i;
const SHORT_FLAG_TEXT_PATTERN = /^(country|geo|pol|political|meme|memeflag|memeflags|pony|mlp):([a-z0-9-]+)$/i;
const COUNTRY_EMOJI_TEXT_PATTERN = /^([a-z]{2}|catalonia|eu|fam|xe|xs|xw|xk|xx)-emoji$/i;
@@ -46,6 +49,7 @@ export interface AuthorFlagViewModel {
type: 'country' | BoardFlagKind;
code: string;
label: string;
labelKey?: string;
spritePath: string;
width: number;
height: number;
@@ -161,7 +165,8 @@ const toCountryFlagViewModel = (codeValue: string): AuthorFlagViewModel | undefi
key: `country:${code}`,
type: 'country',
code,
label: getCountryLabel(code) ?? code.toUpperCase(),
label: code === TOR_COUNTRY_CODE ? TOR_AUTHOR_FLAG_LABEL : (getCountryLabel(code) ?? code.toUpperCase()),
...(code === TOR_COUNTRY_CODE ? { labelKey: TOR_AUTHOR_FLAG_LABEL_KEY } : {}),
spritePath: COUNTRY_FLAG_SPRITE_PATH,
width: COUNTRY_FLAG_WIDTH,
height: COUNTRY_FLAG_HEIGHT,