Merge branch 'feature/emoji-grid' of https://github.com/samunohito/misskey into pr/13473

This commit is contained in:
syuilo 2024-06-13 10:14:37 +09:00
commit 1bb237126c
5 changed files with 76 additions and 67 deletions

View File

@ -3,6 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import seedrandom from 'seedrandom';
/** /**
* AIで生成した無作為なファーストネーム * AIで生成した無作為なファーストネーム
*/ */
@ -30,18 +32,21 @@ export const countryDict = [
'Vietnam', 'Kenya', 'Saudi Arabia', 'Netherlands', 'Colombia', 'Poland', 'Chile', 'Malaysia', 'Ukraine', 'New Zealand', 'Peru', 'Vietnam', 'Kenya', 'Saudi Arabia', 'Netherlands', 'Colombia', 'Poland', 'Chile', 'Malaysia', 'Ukraine', 'New Zealand', 'Peru',
] ]
export function text(length: number = 10): string { export function text(length: number = 10, seed?: string): string {
let result = ""; let result = "";
// シード値を使う場合、同じ数値が羅列されるが、ランダム文字列という意味では満たせていると思うのでこのまま使っておく
const rand = seed ? seedrandom(seed)() : Math.random();
while (result.length < length) { while (result.length < length) {
result += Math.random().toString(36).substring(2); result += rand.toString(36).substring(2);
} }
return result.substring(0, length); return result.substring(0, length);
} }
export function integer(min: number = 0, max: number = 9999): number { export function integer(min: number = 0, max: number = 9999, seed?: string): number {
return Math.floor(Math.random() * (max - min)) + min; const rand = seed ? seedrandom(seed)() : Math.random();
return Math.floor(rand * (max - min)) + min;
} }
export function date(params?: { export function date(params?: {
@ -59,10 +64,10 @@ export function date(params?: {
secondMax?: number, secondMax?: number,
millisecondMin?: number, millisecondMin?: number,
millisecondMax?: number, millisecondMax?: number,
}) { }, seed?: string): Date {
const year = integer(params?.yearMin ?? 1970, params?.yearMax ?? (new Date()).getFullYear()); const year = integer(params?.yearMin ?? 1970, params?.yearMax ?? (new Date()).getFullYear(), seed);
const month = integer(params?.monthMin ?? 1, params?.monthMax ?? 12); const month = integer(params?.monthMin ?? 1, params?.monthMax ?? 12, seed);
let day = integer(params?.dayMin ?? 1, params?.dayMax ?? 31); let day = integer(params?.dayMin ?? 1, params?.dayMax ?? 31, seed);
if (month === 2) { if (month === 2) {
day = Math.min(day, 28); day = Math.min(day, 28);
} else if ([4, 6, 9, 11].includes(month)) { } else if ([4, 6, 9, 11].includes(month)) {
@ -71,43 +76,45 @@ export function date(params?: {
day = Math.min(day, 31); day = Math.min(day, 31);
} }
const hour = integer(params?.hourMin ?? 0, params?.hourMax ?? 23); const hour = integer(params?.hourMin ?? 0, params?.hourMax ?? 23, seed);
const minute = integer(params?.minuteMin ?? 0, params?.minuteMax ?? 59); const minute = integer(params?.minuteMin ?? 0, params?.minuteMax ?? 59, seed);
const second = integer(params?.secondMin ?? 0, params?.secondMax ?? 59); const second = integer(params?.secondMin ?? 0, params?.secondMax ?? 59, seed);
const millisecond = integer(params?.millisecondMin ?? 0, params?.millisecondMax ?? 999); const millisecond = integer(params?.millisecondMin ?? 0, params?.millisecondMax ?? 999, seed);
return new Date(year, month - 1, day, hour, minute, second, millisecond); return new Date(year, month - 1, day, hour, minute, second, millisecond);
} }
export function boolean(): boolean { export function boolean(seed?: string): boolean {
return Math.random() < 0.5; const rand = seed ? seedrandom(seed)() : Math.random();
return rand < 0.5;
} }
export function choose<T>(array: T[]): T { export function choose<T>(array: T[], seed?: string): T {
return array[Math.floor(Math.random() * array.length)]; const rand = seed ? seedrandom(seed)() : Math.random();
return array[Math.floor(rand * array.length)];
} }
export function firstName(): string { export function firstName(seed?: string): string {
return choose(firstNameDict); return choose(firstNameDict, seed);
} }
export function lastName(): string { export function lastName(seed?: string): string {
return choose(lastNameDict); return choose(lastNameDict, seed);
} }
export function country(): string { export function country(seed?: string): string {
return choose(countryDict); return choose(countryDict, seed);
} }
const TIME2000 = 946684800000; const TIME2000 = 946684800000;
export function fakeId(): string { export function fakeId(seed?: string): string {
let time = new Date().getTime(); let time = new Date().getTime();
time = time - TIME2000; time = time - TIME2000;
if (time < 0) time = 0; if (time < 0) time = 0;
const timeStr = time.toString(36).padStart(8, '0'); const timeStr = time.toString(36).padStart(8, '0');
const noiseStr = text(2); const noiseStr = text(2, seed);
return timeStr + noiseStr; return timeStr + noiseStr;
} }
@ -123,7 +130,7 @@ export function imageDataUrl(options?: {
blue?: number, blue?: number,
alpha?: number, alpha?: number,
} }
}): string { }, seed?: string): string {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.width = options?.size?.width ?? 100; canvas.width = options?.size?.width ?? 100;
canvas.height = options?.size?.height ?? 100; canvas.height = options?.size?.height ?? 100;
@ -135,9 +142,9 @@ export function imageDataUrl(options?: {
ctx.beginPath() ctx.beginPath()
const red = options?.color?.red ?? integer(0, 255); const red = options?.color?.red ?? integer(0, 255, seed);
const green = options?.color?.green ?? integer(0, 255); const green = options?.color?.green ?? integer(0, 255, seed);
const blue = options?.color?.blue ?? integer(0, 255); const blue = options?.color?.blue ?? integer(0, 255, seed);
const alpha = options?.color?.alpha ?? 1; const alpha = options?.color?.alpha ?? 1;
ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2, true); ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2, true);
ctx.fillStyle = `rgba(${red}, ${green}, ${blue}, ${alpha})`; ctx.fillStyle = `rgba(${red}, ${green}, ${blue}, ${alpha})`;

View File

@ -4,7 +4,7 @@
*/ */
import type { entities } from 'misskey-js' import type { entities } from 'misskey-js'
import { imageDataUrl, text } from "./fake-utils.js"; import { date, imageDataUrl, text } from "./fake-utils.js";
export function abuseUserReport() { export function abuseUserReport() {
return { return {
@ -232,9 +232,11 @@ export function role(params: {
asBadge?: boolean, asBadge?: boolean,
canEditMembersByModerator?: boolean, canEditMembersByModerator?: boolean,
usersCount?: number, usersCount?: number,
}): entities.Role { }, seed?: string): entities.Role {
const prefix = params.displayOrder ? params.displayOrder.toString().padStart(3, '0') + '-' : ''; const prefix = params.displayOrder ? params.displayOrder.toString().padStart(3, '0') + '-' : '';
const genId = Math.random().toString(36).substring(10); const genId = text(36, seed);
const createdAt = params.createdAt ?? date({}, seed).toISOString();
const updatedAt = params.updatedAt ?? date({}, seed).toISOString();
return { return {
id: params.id ?? genId, id: params.id ?? genId,
@ -245,8 +247,8 @@ export function role(params: {
isModerator: params.isModerator ?? false, isModerator: params.isModerator ?? false,
isAdministrator: params.isAdministrator ?? false, isAdministrator: params.isAdministrator ?? false,
displayOrder: params.displayOrder ?? 0, displayOrder: params.displayOrder ?? 0,
createdAt: params.createdAt ?? new Date().toISOString(), createdAt: createdAt,
updatedAt: params.updatedAt ?? new Date().toISOString(), updatedAt: updatedAt,
target: params.target ?? 'manual', target: params.target ?? 'manual',
isPublic: params.isPublic ?? true, isPublic: params.isPublic ?? true,
isExplorable: params.isExplorable ?? true, isExplorable: params.isExplorable ?? true,
@ -277,11 +279,13 @@ export function emoji(params?: {
localOnly?: boolean, localOnly?: boolean,
roleIdsThatCanBeUsedThisEmojiAsReaction?: {id:string, name:string}[], roleIdsThatCanBeUsedThisEmojiAsReaction?: {id:string, name:string}[],
updatedAt?: string, updatedAt?: string,
}): entities.EmojiDetailedAdmin { }, seed?: string): entities.EmojiDetailedAdmin {
const id = params?.id ?? new Date().getTime().toString() + text(5); const _seed = seed ?? (params?.id ?? "DEFAULT_SEED");
const name = params?.name ?? text(8); const id = params?.id ?? text(32, _seed);
const name = params?.name ?? text(8, _seed);
const updatedAt = params?.updatedAt ?? date({}, _seed).toISOString();
const image = imageDataUrl() const image = imageDataUrl({}, _seed)
return { return {
id: id, id: id,
@ -297,6 +301,6 @@ export function emoji(params?: {
isSensitive: params?.isSensitive ?? false, isSensitive: params?.isSensitive ?? false,
localOnly: params?.localOnly ?? false, localOnly: params?.localOnly ?? false,
roleIdsThatCanBeUsedThisEmojiAsReaction: params?.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [], roleIdsThatCanBeUsedThisEmojiAsReaction: params?.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [],
updatedAt: params?.updatedAt ?? new Date().toISOString(), updatedAt: updatedAt,
} }
} }

View File

@ -11,10 +11,10 @@ import { commonHandlers } from '../../.storybook/mocks.js';
import MkRoleSelectDialog from '@/components/MkRoleSelectDialog.vue'; import MkRoleSelectDialog from '@/components/MkRoleSelectDialog.vue';
const roles = [ const roles = [
role({ displayOrder: 1 }), role({ displayOrder: 1 }), role({ displayOrder: 1 }), role({ displayOrder: 1 }), role({ displayOrder: 1 }, '1'), role({ displayOrder: 1 }, '1'), role({ displayOrder: 1 }, '1'), role({ displayOrder: 1 }, '1'),
role({ displayOrder: 2 }), role({ displayOrder: 2 }), role({ displayOrder: 3 }), role({ displayOrder: 3 }), role({ displayOrder: 2 }, '2'), role({ displayOrder: 2 }, '2'), role({ displayOrder: 3 }, '3'), role({ displayOrder: 3 }, '3'),
role({ displayOrder: 4 }), role({ displayOrder: 5 }), role({ displayOrder: 6 }), role({ displayOrder: 7 }), role({ displayOrder: 4 }, '4'), role({ displayOrder: 5 }, '5'), role({ displayOrder: 6 }, '6'), role({ displayOrder: 7 }, '7'),
role({ displayOrder: 999, name: 'privateRole', isPublic: false }), role({ displayOrder: 999, name: 'privateRole', isPublic: false }, '999'),
]; ];
export const Default = { export const Default = {

View File

@ -12,6 +12,7 @@ import { boolean, choose, country, date, firstName, integer, lastName, text } fr
import MkGrid from './MkGrid.vue'; import MkGrid from './MkGrid.vue';
import { GridContext, GridEvent } from '@/components/grid/grid-event.js'; import { GridContext, GridEvent } from '@/components/grid/grid-event.js';
import { DataSource, GridSetting } from '@/components/grid/grid.js'; import { DataSource, GridSetting } from '@/components/grid/grid.js';
import { GridColumnSetting } from '@/components/grid/column.js';
function d(p: { function d(p: {
check?: boolean, check?: boolean,
@ -23,23 +24,23 @@ function d(p: {
country?: string, country?: string,
reportCount?: number, reportCount?: number,
createdAt?: string, createdAt?: string,
}) { }, seed: string) {
const prefix = text(10); const prefix = text(10, seed);
return { return {
check: p.check ?? boolean(), check: p.check ?? boolean(seed),
name: p.name ?? `${firstName()} ${lastName()}`, name: p.name ?? `${firstName(seed)} ${lastName(seed)}`,
email: p.email ?? `${prefix}@example.com`, email: p.email ?? `${prefix}@example.com`,
age: p.age ?? integer(20, 80), age: p.age ?? integer(20, 80, seed),
birthday: date().toISOString(), birthday: date({}, seed).toISOString(),
gender: p.gender ?? choose(['male', 'female', 'other', 'unknown']), gender: p.gender ?? choose(['male', 'female', 'other', 'unknown'], seed),
country: p.country ?? country(), country: p.country ?? country(seed),
reportCount: p.reportCount ?? integer(), reportCount: p.reportCount ?? integer(0, 9999, seed),
createdAt: p.createdAt ?? date().toISOString(), createdAt: p.createdAt ?? date({}, seed).toISOString(),
}; };
} }
const defaultCols = [ const defaultCols: GridColumnSetting[] = [
{ bindTo: 'check', icon: 'ti-check', type: 'boolean', width: 50 }, { bindTo: 'check', icon: 'ti-check', type: 'boolean', width: 50 },
{ bindTo: 'name', title: 'Name', type: 'text', width: 'auto' }, { bindTo: 'name', title: 'Name', type: 'text', width: 'auto' },
{ bindTo: 'email', title: 'Email', type: 'text', width: 'auto' }, { bindTo: 'email', title: 'Email', type: 'text', width: 'auto' },
@ -52,13 +53,10 @@ const defaultCols = [
]; ];
function createArgs(overrides?: { settings?: Partial<GridSetting>, data?: DataSource[] }) { function createArgs(overrides?: { settings?: Partial<GridSetting>, data?: DataSource[] }) {
const refData = ref([ const refData = ref<ReturnType<typeof d>[]>([]);
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), for (let i = 0; i < 100; i++) {
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), refData.value.push(d({}, i.toString()));
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), }
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}), d({}),
]);
return { return {
settings: { settings: {
@ -73,7 +71,7 @@ function createArgs(overrides?: { settings?: Partial<GridSetting>, data?: DataSo
}; };
} }
function createRender(params: { settings: Partial<GridSetting>, data: DataSource[] }) { function createRender(params: { settings: GridSetting, data: DataSource[] }) {
return { return {
render(args) { render(args) {
return { return {
@ -155,7 +153,7 @@ export const AdditionalRowStyle = createRender(createArgs({
row: { row: {
styleRules: [ styleRules: [
{ {
condition: ({ row }) => AdditionalRowStyle.args.data[row.index].check, condition: ({ row }) => AdditionalRowStyle.args.data[row.index].check as boolean,
applyStyle: { applyStyle: {
style: { style: {
backgroundColor: 'lightgray', backgroundColor: 'lightgray',

View File

@ -89,7 +89,7 @@ function createRender(params: {
}); });
const driveFile: entities.DriveFile = { const driveFile: entities.DriveFile = {
id: fakeId(), id: fakeId(file.name),
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
name: file.name, name: file.name,
type: file.type, type: file.type,
@ -122,7 +122,7 @@ function createRender(params: {
const file = storedDriveFiles.find(f => f.id === fileId)!; const file = storedDriveFiles.find(f => f.id === fileId)!;
const em = emoji({ const em = emoji({
id: fakeId(), id: fakeId(file.name),
name: body.name, name: body.name,
publicUrl: file.url, publicUrl: file.url,
originalUrl: file.url, originalUrl: file.url,
@ -148,13 +148,13 @@ export const Default = createRender({
}); });
export const List10 = createRender({ export const List10 = createRender({
emojis: Array.from({ length: 10 }, (_, i) => emoji({ name: `emoji_${i}` })), emojis: Array.from({ length: 10 }, (_, i) => emoji({ name: `emoji_${i}` }, i.toString())),
}); });
export const List100 = createRender({ export const List100 = createRender({
emojis: Array.from({ length: 100 }, (_, i) => emoji({ name: `emoji_${i}` })), emojis: Array.from({ length: 100 }, (_, i) => emoji({ name: `emoji_${i}` }, i.toString())),
}); });
export const List1000 = createRender({ export const List1000 = createRender({
emojis: Array.from({ length: 1000 }, (_, i) => emoji({ name: `emoji_${i}` })), emojis: Array.from({ length: 1000 }, (_, i) => emoji({ name: `emoji_${i}` }, i.toString())),
}); });