mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(flags): align board flag rendering (#1142)
* fix(flags): align board flag rendering * ci: run react doctor on changed pr files
This commit is contained in:
@@ -89,9 +89,13 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Run React Doctor
|
- name: Run React Doctor
|
||||||
if: github.event_name != 'pull_request' || steps.react-ui-changes.outputs.changed == 'true'
|
if: github.event_name != 'pull_request'
|
||||||
run: yarn doctor
|
run: yarn doctor
|
||||||
|
|
||||||
|
- name: Run React Doctor on changed React files
|
||||||
|
if: github.event_name == 'pull_request' && steps.react-ui-changes.outputs.changed == 'true'
|
||||||
|
run: yarn doctor --diff "${{ github.event.pull_request.base.sha }}" --annotations
|
||||||
|
|
||||||
- name: Skip React Doctor
|
- name: Skip React Doctor
|
||||||
if: github.event_name == 'pull_request' && steps.react-ui-changes.outputs.changed != 'true'
|
if: github.event_name == 'pull_request' && steps.react-ui-changes.outputs.changed != 'true'
|
||||||
run: echo "Skipping React Doctor because this pull request did not change React UI source."
|
run: echo "Skipping React Doctor because this pull request did not change React UI source."
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import { getThreadPostCountsByAuthor } from '../../lib/utils/author-post-counts'
|
|||||||
import { withResolvedCommentCommunityAddress } from '../../lib/utils/comment-utils';
|
import { withResolvedCommentCommunityAddress } from '../../lib/utils/comment-utils';
|
||||||
import { getFeedPostHeightEstimate, getReplyHeightEstimates, reportReplyHeightAuditSample } from '../../lib/utils/pretext-height-estimates';
|
import { getFeedPostHeightEstimate, getReplyHeightEstimates, reportReplyHeightAuditSample } from '../../lib/utils/pretext-height-estimates';
|
||||||
import { getAuthorBadge } from '../../lib/utils/author-display-utils';
|
import { getAuthorBadge } from '../../lib/utils/author-display-utils';
|
||||||
|
import { hasCommentFlagsForDirectory } from '../../lib/comment-flag-selection';
|
||||||
|
|
||||||
const { addChallenge } = useChallengesStore.getState();
|
const { addChallenge } = useChallengesStore.getState();
|
||||||
|
|
||||||
@@ -242,7 +243,7 @@ const PostInfo = ({
|
|||||||
const directories = useDirectories();
|
const directories = useDirectories();
|
||||||
const directoryEntry = communityAddress ? findDirectoryByAddress(directories, communityAddress) : undefined;
|
const directoryEntry = communityAddress ? findDirectoryByAddress(directories, communityAddress) : undefined;
|
||||||
const boardPath = communityAddress ? getBoardPath(communityAddress, directories) : undefined;
|
const boardPath = communityAddress ? getBoardPath(communityAddress, directories) : undefined;
|
||||||
const showAuthorFlags = directoryEntry?.features?.hasFlags === true && !(deleted || removed || purged);
|
const showAuthorFlags = hasCommentFlagsForDirectory(directoryEntry) && !(deleted || removed || purged);
|
||||||
const postMenuProps = selectPostMenuProps(post);
|
const postMenuProps = selectPostMenuProps(post);
|
||||||
|
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import { getThreadPostCountsByAuthor } from '../../lib/utils/author-post-counts'
|
|||||||
import { withResolvedCommentCommunityAddress } from '../../lib/utils/comment-utils';
|
import { withResolvedCommentCommunityAddress } from '../../lib/utils/comment-utils';
|
||||||
import { getFeedPostHeightEstimate, getReplyHeightEstimates, reportReplyHeightAuditSample } from '../../lib/utils/pretext-height-estimates';
|
import { getFeedPostHeightEstimate, getReplyHeightEstimates, reportReplyHeightAuditSample } from '../../lib/utils/pretext-height-estimates';
|
||||||
import { getAuthorBadge } from '../../lib/utils/author-display-utils';
|
import { getAuthorBadge } from '../../lib/utils/author-display-utils';
|
||||||
|
import { hasCommentFlagsForDirectory } from '../../lib/comment-flag-selection';
|
||||||
|
|
||||||
const { addChallenge } = useChallengesStore.getState();
|
const { addChallenge } = useChallengesStore.getState();
|
||||||
|
|
||||||
@@ -89,7 +90,7 @@ const PostInfoAndMedia = ({
|
|||||||
const purged = resolvedPost?.commentModeration?.purged;
|
const purged = resolvedPost?.commentModeration?.purged;
|
||||||
const boardPath = communityAddress ? getBoardPath(communityAddress, directories) : undefined;
|
const boardPath = communityAddress ? getBoardPath(communityAddress, directories) : undefined;
|
||||||
const directoryEntry = communityAddress ? findDirectoryByAddress(directories, communityAddress) : undefined;
|
const directoryEntry = communityAddress ? findDirectoryByAddress(directories, communityAddress) : undefined;
|
||||||
const showAuthorFlags = directoryEntry?.features?.hasFlags === true && !(deleted || removed || purged);
|
const showAuthorFlags = hasCommentFlagsForDirectory(directoryEntry) && !(deleted || removed || purged);
|
||||||
const displayBoardPath =
|
const displayBoardPath =
|
||||||
boardPath && communityAddress
|
boardPath && communityAddress
|
||||||
? boardPath !== communityAddress
|
? boardPath !== communityAddress
|
||||||
|
|||||||
@@ -19,6 +19,30 @@ describe('board-flags', () => {
|
|||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
});
|
});
|
||||||
|
expect(getBoardFlagDefinition('pol', 'MZ')).toMatchObject({
|
||||||
|
code: 'MZ',
|
||||||
|
label: 'Task Force Z',
|
||||||
|
x: 64,
|
||||||
|
y: 24,
|
||||||
|
});
|
||||||
|
expect(getBoardFlagDefinition('pol', 'NB')).toMatchObject({
|
||||||
|
code: 'NB',
|
||||||
|
label: 'National Bolshevik',
|
||||||
|
x: 0,
|
||||||
|
y: 36,
|
||||||
|
});
|
||||||
|
expect(getBoardFlagDefinition('pol', 'RE')).toMatchObject({
|
||||||
|
code: 'RE',
|
||||||
|
label: 'Republican',
|
||||||
|
x: 0,
|
||||||
|
y: 48,
|
||||||
|
});
|
||||||
|
expect(getBoardFlagDefinition('pol', 'TM')).toMatchObject({
|
||||||
|
code: 'TM',
|
||||||
|
label: 'Templar',
|
||||||
|
x: 16,
|
||||||
|
y: 48,
|
||||||
|
});
|
||||||
expect(getBoardFlagDefinition('pol', 'WP')).toMatchObject({ code: 'WP', x: 64, y: 48 });
|
expect(getBoardFlagDefinition('pol', 'WP')).toMatchObject({ code: 'WP', x: 64, y: 48 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
getCommentFlagPublishOptionsForDirectory,
|
getCommentFlagPublishOptionsForDirectory,
|
||||||
getCommentFlagPublishOptionsFromSelection,
|
getCommentFlagPublishOptionsFromSelection,
|
||||||
getCommentFlagRequestFromSelection,
|
getCommentFlagRequestFromSelection,
|
||||||
|
hasCommentFlagsForDirectory,
|
||||||
} from '../comment-flag-selection';
|
} from '../comment-flag-selection';
|
||||||
|
|
||||||
describe('comment-flag-selection', () => {
|
describe('comment-flag-selection', () => {
|
||||||
@@ -11,6 +12,11 @@ describe('comment-flag-selection', () => {
|
|||||||
expect(getCommentFlagOptionsForDirectory({ features: {}, title: '/mu/ - Music' })).toEqual([]);
|
expect(getCommentFlagOptionsForDirectory({ features: {}, title: '/mu/ - Music' })).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('detects flag-capable directories from directory metadata', () => {
|
||||||
|
expect(hasCommentFlagsForDirectory({ features: {}, title: '/mu/ - Music' })).toBe(false);
|
||||||
|
expect(hasCommentFlagsForDirectory({ features: { hasFlags: true }, title: '/pol/ - Politically Incorrect' })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('uses geographic location as the default for country flag boards', () => {
|
it('uses geographic location as the default for country flag boards', () => {
|
||||||
expect(
|
expect(
|
||||||
getCommentFlagOptionsForDirectory({
|
getCommentFlagOptionsForDirectory({
|
||||||
@@ -59,6 +65,14 @@ describe('comment-flag-selection', () => {
|
|||||||
{ label: 'Confederate', value: 'pol:CF' },
|
{ label: 'Confederate', value: 'pol:CF' },
|
||||||
{ label: 'Communist', value: 'pol:CM' },
|
{ label: 'Communist', value: 'pol:CM' },
|
||||||
]);
|
]);
|
||||||
|
expect(options.slice(-6)).toEqual([
|
||||||
|
{ label: 'Republican', value: 'pol:RE' },
|
||||||
|
{ label: 'Task Force Z', value: 'pol:MZ' },
|
||||||
|
{ label: 'Templar', value: 'pol:TM' },
|
||||||
|
{ label: 'Tree Hugger', value: 'pol:TR' },
|
||||||
|
{ label: 'United Nations', value: 'pol:UN' },
|
||||||
|
{ label: 'White Supremacist', value: 'pol:WP' },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('matches the 4chan /mlp/ flag default', () => {
|
it('matches the 4chan /mlp/ flag default', () => {
|
||||||
|
|||||||
+47
-6
@@ -21,6 +21,7 @@ const PONY_FLAG_HEIGHT = 16;
|
|||||||
const PONY_FLAG_COLUMNS = 9;
|
const PONY_FLAG_COLUMNS = 9;
|
||||||
const PONY_FLAG_SPRITE_PATH = 'assets/icons/flags-pony.png';
|
const PONY_FLAG_SPRITE_PATH = 'assets/icons/flags-pony.png';
|
||||||
|
|
||||||
|
// Order follows 4chan's board flag selector. Coordinates follow flags/pol/flags.2.css.
|
||||||
const POLITICAL_FLAG_ENTRIES = [
|
const POLITICAL_FLAG_ENTRIES = [
|
||||||
['AC', 'Anarcho-Capitalist'],
|
['AC', 'Anarcho-Capitalist'],
|
||||||
['AN', 'Anarchist'],
|
['AN', 'Anarchist'],
|
||||||
@@ -42,13 +43,41 @@ const POLITICAL_FLAG_ENTRIES = [
|
|||||||
['PC', 'Hippie'],
|
['PC', 'Hippie'],
|
||||||
['PR', 'Pirate'],
|
['PR', 'Pirate'],
|
||||||
['RE', 'Republican'],
|
['RE', 'Republican'],
|
||||||
['TM', 'Templar'],
|
|
||||||
['MZ', 'Task Force Z'],
|
['MZ', 'Task Force Z'],
|
||||||
|
['TM', 'Templar'],
|
||||||
['TR', 'Tree Hugger'],
|
['TR', 'Tree Hugger'],
|
||||||
['UN', 'United Nations'],
|
['UN', 'United Nations'],
|
||||||
['WP', 'White Supremacist'],
|
['WP', 'White Supremacist'],
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
const POLITICAL_FLAG_COORDINATES = {
|
||||||
|
AC: [0, 0],
|
||||||
|
AN: [16, 0],
|
||||||
|
BL: [32, 0],
|
||||||
|
CF: [48, 0],
|
||||||
|
CM: [64, 0],
|
||||||
|
CT: [0, 12],
|
||||||
|
DM: [16, 12],
|
||||||
|
EU: [32, 12],
|
||||||
|
FC: [48, 12],
|
||||||
|
GN: [64, 12],
|
||||||
|
GY: [0, 24],
|
||||||
|
JH: [16, 24],
|
||||||
|
KN: [32, 24],
|
||||||
|
MF: [48, 24],
|
||||||
|
MZ: [64, 24],
|
||||||
|
NB: [0, 36],
|
||||||
|
NT: [16, 36],
|
||||||
|
NZ: [32, 36],
|
||||||
|
PC: [48, 36],
|
||||||
|
PR: [64, 36],
|
||||||
|
RE: [0, 48],
|
||||||
|
TM: [16, 48],
|
||||||
|
TR: [32, 48],
|
||||||
|
UN: [48, 48],
|
||||||
|
WP: [64, 48],
|
||||||
|
} as const satisfies Record<(typeof POLITICAL_FLAG_ENTRIES)[number][0], readonly [number, number]>;
|
||||||
|
|
||||||
const PONY_FLAG_ENTRIES = [
|
const PONY_FLAG_ENTRIES = [
|
||||||
['4CC', '4cc /mlp/'],
|
['4CC', '4cc /mlp/'],
|
||||||
['ADA', 'Adagio Dazzle'],
|
['ADA', 'Adagio Dazzle'],
|
||||||
@@ -144,9 +173,12 @@ const buildFlagDefinitions = (
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
columns: number,
|
columns: number,
|
||||||
|
coordinatesByCode?: Readonly<Record<string, readonly [number, number]>>,
|
||||||
): ReadonlyMap<string, BoardFlagDefinition> =>
|
): ReadonlyMap<string, BoardFlagDefinition> =>
|
||||||
new Map(
|
new Map(
|
||||||
entries.map(([code, label], index) => [
|
entries.map(([code, label], index) => {
|
||||||
|
const [x, y] = coordinatesByCode?.[code] ?? [(index % columns) * width, Math.floor(index / columns) * height];
|
||||||
|
return [
|
||||||
code,
|
code,
|
||||||
{
|
{
|
||||||
kind,
|
kind,
|
||||||
@@ -155,14 +187,23 @@ const buildFlagDefinitions = (
|
|||||||
spritePath,
|
spritePath,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
x: (index % columns) * width,
|
x,
|
||||||
y: Math.floor(index / columns) * height,
|
y,
|
||||||
},
|
},
|
||||||
]),
|
] as const;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const BOARD_FLAGS_BY_KIND: Record<BoardFlagKind, ReadonlyMap<string, BoardFlagDefinition>> = {
|
const BOARD_FLAGS_BY_KIND: Record<BoardFlagKind, ReadonlyMap<string, BoardFlagDefinition>> = {
|
||||||
pol: buildFlagDefinitions(POLITICAL_FLAG_ENTRIES, 'pol', POLITICAL_FLAG_SPRITE_PATH, POLITICAL_FLAG_WIDTH, POLITICAL_FLAG_HEIGHT, POLITICAL_FLAG_COLUMNS),
|
pol: buildFlagDefinitions(
|
||||||
|
POLITICAL_FLAG_ENTRIES,
|
||||||
|
'pol',
|
||||||
|
POLITICAL_FLAG_SPRITE_PATH,
|
||||||
|
POLITICAL_FLAG_WIDTH,
|
||||||
|
POLITICAL_FLAG_HEIGHT,
|
||||||
|
POLITICAL_FLAG_COLUMNS,
|
||||||
|
POLITICAL_FLAG_COORDINATES,
|
||||||
|
),
|
||||||
pony: buildFlagDefinitions(PONY_FLAG_ENTRIES, 'pony', PONY_FLAG_SPRITE_PATH, PONY_FLAG_WIDTH, PONY_FLAG_HEIGHT, PONY_FLAG_COLUMNS),
|
pony: buildFlagDefinitions(PONY_FLAG_ENTRIES, 'pony', PONY_FLAG_SPRITE_PATH, PONY_FLAG_WIDTH, PONY_FLAG_HEIGHT, PONY_FLAG_COLUMNS),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export interface CommentFlagPublishOptions {
|
|||||||
flairs: CommentFlagRequest[] | undefined;
|
flairs: CommentFlagRequest[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CommentFlagDirectory = Partial<Pick<DirectoryCommunity, 'directoryCode' | 'features' | 'title'>>;
|
||||||
|
|
||||||
const GEOGRAPHIC_LOCATION_OPTION: CommentFlagSelectOption = {
|
const GEOGRAPHIC_LOCATION_OPTION: CommentFlagSelectOption = {
|
||||||
value: GEOGRAPHIC_LOCATION_FLAG_VALUE,
|
value: GEOGRAPHIC_LOCATION_FLAG_VALUE,
|
||||||
label: 'Geographic Location',
|
label: 'Geographic Location',
|
||||||
@@ -43,14 +45,18 @@ const getDirectoryCode = (directory: Pick<DirectoryCommunity, 'directoryCode' |
|
|||||||
return directoryCode || directory?.title?.match(/^\/([^/]+)\//)?.[1]?.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[] =>
|
const getBoardFlagOptions = (kind: BoardFlagKind): CommentFlagSelectOption[] =>
|
||||||
getBoardFlagDefinitions(kind).map((flag) => ({
|
getBoardFlagDefinitions(kind).map((flag) => ({
|
||||||
value: `${flag.kind}:${flag.code}`,
|
value: `${flag.kind}:${flag.code}`,
|
||||||
label: flag.label,
|
label: flag.label,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const getCommentFlagOptionsForDirectory = (directory: Pick<DirectoryCommunity, 'directoryCode' | 'features' | 'title'> | undefined): CommentFlagSelectOption[] => {
|
export const getCommentFlagOptionsForDirectory = (directory: CommentFlagDirectory | undefined): CommentFlagSelectOption[] => {
|
||||||
if (directory?.features?.hasFlags !== true) {
|
if (!hasCommentFlagsForDirectory(directory)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +76,8 @@ export const getCommentFlagOptionsForDirectory = (directory: Pick<DirectoryCommu
|
|||||||
return [GEOGRAPHIC_LOCATION_OPTION];
|
return [GEOGRAPHIC_LOCATION_OPTION];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCommentFlagPublishOptionsForDirectory = (
|
export const getCommentFlagPublishOptionsForDirectory = (directory: CommentFlagDirectory | undefined, selectedValue?: string): CommentFlagPublishOptions => {
|
||||||
directory: Pick<DirectoryCommunity, 'directoryCode' | 'features' | 'title'> | undefined,
|
if (!hasCommentFlagsForDirectory(directory)) {
|
||||||
selectedValue?: string,
|
|
||||||
): CommentFlagPublishOptions => {
|
|
||||||
if (directory?.features?.hasFlags !== true) {
|
|
||||||
return {
|
return {
|
||||||
challengeRequest: undefined,
|
challengeRequest: undefined,
|
||||||
flairs: undefined,
|
flairs: undefined,
|
||||||
|
|||||||
Reference in New Issue
Block a user