Skip to content

Commit 457a43e

Browse files
committed
Listen for username color tags on messages
- In addition to tagmsg, check tags on messages (PRIVMSG, ACTION, NOTICE) for username colors - Add named colors and test to ensure color values are accessible
1 parent e3b99ac commit 457a43e

3 files changed

Lines changed: 37 additions & 12 deletions

File tree

src/stores/user-list.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ANONYMOUS_USER, DEFAULT_COLORS } from '#constants';
22
import type { User } from '#models';
33
import { getUserProfile } from '#services';
4-
import { isValidHexColor, parseNick, parseUid } from '#utils';
4+
import { isAccessibleHexColor, parseNick, parseUid } from '#utils';
55
import log from 'loglevel';
66
import { defineStore } from 'pinia';
77
import { computed, reactive, readonly, watch } from 'vue';
@@ -88,7 +88,10 @@ const useUserListStore = defineStore('userList', () => {
8888
user.awayReason = '';
8989
}
9090

91-
function updateUserColor(nick: string, color: string) {
91+
function updateUserColor(nick: string, color?: string) {
92+
if (typeof color !== 'string' || !isAccessibleHexColor(color)) {
93+
return;
94+
}
9295
const username = parseNick(nick);
9396
const user = knownUsers.get(username);
9497
if (!user) {
@@ -152,11 +155,10 @@ const useUserListStore = defineStore('userList', () => {
152155
.on('tagmsg', (event) => {
153156
// Using '+color' client-tag for updating username color
154157
// See https://ircv3.net/specs/extensions/message-tags
155-
const nick = event.nick;
156-
const color = event.tags['+color'];
157-
if (typeof color === 'string' && isValidHexColor(color)) {
158-
updateUserColor(nick, color);
159-
}
158+
updateUserColor(event.nick, event.tags['+color']);
159+
})
160+
.on('message', (event) => {
161+
updateUserColor(event.nick, event.tags['+color']);
160162
});
161163
},
162164
);

src/utils/colors.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { isAccessibleHexColor, NAMED_COLORS } from './colors';
3+
4+
describe('colors', () => {
5+
it('ensures all named colors are accessible', () => {
6+
for (const [name, hexValue] of Object.entries(NAMED_COLORS)) {
7+
// oxlint-disable-next-line jest/valid-expect Vitest allows a second argument for error messages
8+
expect(isAccessibleHexColor(hexValue), `${name} is not accessible`).toBe(true);
9+
}
10+
});
11+
});

src/utils/colors.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,28 @@ export function brightness(r: number, g: number, b: number) {
1616

1717
const BACKGROUND_VALUE = brightness(4, 52, 104);
1818
/** Determines whether color contrasts well with background */
19-
export function isValidColor(r: number, g: number, b: number) {
19+
export function isAccessibleColor(r: number, g: number, b: number) {
2020
const colorValue = brightness(r, g, b);
2121
return Math.abs((colorValue + 0.05) / (BACKGROUND_VALUE + 0.05)) > 4;
2222
}
2323

24-
/** See {@link isValidColor} */
25-
export function isValidHexColor(hex: string) {
26-
if (hex.length !== 7) {
24+
/** See {@link isAccessibleColor} */
25+
export function isAccessibleHexColor(hex: string) {
26+
if (!/^#[0-9a-f]{6}$/i.test(hex)) {
2727
return false;
2828
}
2929
const { r, g, b } = hexToRGB(hex);
30-
return isValidColor(r, g, b);
30+
return isAccessibleColor(r, g, b);
31+
}
32+
33+
export const NAMED_COLORS: Record<string, string> = {
34+
orange: '#ffb400',
35+
yellow: '#ffff00',
36+
blue: '#00f8ff',
37+
green: '#53ff00',
38+
purple: '#ff76ff',
39+
};
40+
41+
export function getNamedColor(colorName: string): string | null {
42+
return NAMED_COLORS[colorName] ?? null;
3143
}

0 commit comments

Comments
 (0)