This commit is contained in:
kakkokari-gtyih 2025-05-04 19:20:19 +09:00
parent 96012a59f8
commit 6274b371cf
4 changed files with 65 additions and 87 deletions

View File

@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed } from 'vue';
import { getTickerColors, getTickerInfo } from '@/scripts/tms/instance-ticker.js';
import { getTickerColors, getTickerInfo } from '@/utility/instance-ticker.js';
export type TickerProps = {
readonly instance?: {

View File

@ -1,63 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export type HEX = string;
export type RGB = {
readonly r: number;
readonly g: number;
readonly b: number;
};
const DEFAULT_HEX = '#ff0000' as const satisfies HEX;
const DEFAULT_RGB = { r: 255, g: 0, b: 0 } as const satisfies RGB;
export const hexToRgb = (hex: string): RGB => {
if (hex.startsWith('#')) {
hex = hex.slice(1);
}
if (hex.length === 3) {
if (!validHex(hex)) {
return DEFAULT_RGB;
}
hex = [...hex].map(char => char.repeat(2)).join('');
}
if (!(hex.length === 6 && validHex(hex))) {
return DEFAULT_RGB;
}
const [r, g, b] = Array.from(hex.match(/.{2}/g) ?? [], n => parseInt(n, 16));
return { r, g, b } as const satisfies RGB;
};
export const rgbToHex = (rgb: RGB): HEX => {
if (!validRgb(rgb)) {
return DEFAULT_HEX;
}
const toHex2Digit = (n: number): string => {
return (n.toString(16).split('.').at(0) ?? '').padStart(2, '0');
};
const { r, g, b } = rgb;
const hexR = toHex2Digit(r);
const hexG = toHex2Digit(g);
const hexB = toHex2Digit(b);
return `#${hexR}${hexG}${hexB}` as const satisfies HEX;
};
const validHex = (hex: unknown): hex is string => {
if (typeof hex !== 'string') return false;
return /^[0-9a-f]+$/i.test(hex);
};
const validRgb = (rgb: unknown): rgb is RGB => {
if (typeof rgb !== 'object' || rgb == null) return false;
if (!('r' in rgb && 'g' in rgb && 'b' in rgb)) return false;
const validRange = (n: unknown): boolean => {
if (typeof n !== 'number') return false;
if (!Number.isInteger(n)) return false;
return 0 <= n && n <= 255;
};
const { r, g, b } = rgb;
return validRange(r) && validRange(g) && validRange(b);
};

View File

@ -3,6 +3,17 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
export type HEX = string;
export type RGB = {
readonly r: number;
readonly g: number;
readonly b: number;
};
const DEFAULT_HEX = '#ff0000' as const satisfies HEX;
const DEFAULT_RGB = { r: 255, g: 0, b: 0 } as const satisfies RGB;
export const alpha = (hex: string, a: number): string => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;
const r = parseInt(result[1], 16);
@ -10,3 +21,51 @@ export const alpha = (hex: string, a: number): string => {
const b = parseInt(result[3], 16);
return `rgba(${r}, ${g}, ${b}, ${a})`;
};
export const hexToRgb = (hex: string): RGB => {
if (hex.startsWith('#')) {
hex = hex.slice(1);
}
if (hex.length === 3) {
if (!validHex(hex)) {
return DEFAULT_RGB;
}
hex = [...hex].map(char => char.repeat(2)).join('');
}
if (!(hex.length === 6 && validHex(hex))) {
return DEFAULT_RGB;
}
const [r, g, b] = Array.from(hex.match(/.{2}/g) ?? [], n => parseInt(n, 16));
return { r, g, b } as const satisfies RGB;
};
export const rgbToHex = (rgb: RGB): HEX => {
if (!validRgb(rgb)) {
return DEFAULT_HEX;
}
const toHex2Digit = (n: number): string => {
return (n.toString(16).split('.').at(0) ?? '').padStart(2, '0');
};
const { r, g, b } = rgb;
const hexR = toHex2Digit(r);
const hexG = toHex2Digit(g);
const hexB = toHex2Digit(b);
return `#${hexR}${hexG}${hexB}` as const satisfies HEX;
};
const validHex = (hex: unknown): hex is string => {
if (typeof hex !== 'string') return false;
return /^[0-9a-f]+$/i.test(hex);
};
const validRgb = (rgb: unknown): rgb is RGB => {
if (typeof rgb !== 'object' || rgb == null) return false;
if (!('r' in rgb && 'g' in rgb && 'b' in rgb)) return false;
const validRange = (n: unknown): boolean => {
if (typeof n !== 'number') return false;
if (!Number.isInteger(n)) return false;
return 0 <= n && n <= 255;
};
const { r, g, b } = rgb;
return validRange(r) && validRange(g) && validRange(b);
};

View File

@ -3,11 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { host } from '@/config.js';
import { host } from '@@/js/config.js';
import { instance as localInstance } from '@/instance.js';
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
import { type HEX, hexToRgb } from '@/scripts/tms/color.js';
import { type TickerProps } from '@/components/TmsInstanceTicker.vue';
import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js';
import { hexToRgb } from '@/utility/color.js';
import type { HEX } from '@/utility/color.js';
import type { TickerProps } from '@/components/MkInstanceTicker.vue';
//#region ticker info
type TickerInfo = {
@ -78,22 +79,3 @@ export const getTickerColors = (info: TickerInfo): TickerColors => {
return tickerColors;
};
//#endregion ticker colors
//#region ticker state
type TickerState = {
readonly normal: boolean;
readonly vertical: boolean;
readonly watermark: boolean;
readonly left: boolean;
readonly right: boolean;
};
export const getTickerState = (props: TickerProps): TickerState => {
const vertical = props.position === 'leftVerticalBar' || props.position === 'rightVerticalBar';
const watermark = props.position === 'leftWatermark' || props.position === 'rightWatermark';
const normal = !vertical && !watermark;
const left = props.position === 'leftVerticalBar' || props.position === 'leftWatermark';
const right = props.position === 'rightVerticalBar' || props.position === 'rightWatermark';
return { normal, vertical, watermark, left, right } as const satisfies TickerState;
};
//#endregion ticker state