diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index eee5f4128..f9e1757c0 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -32,8 +32,8 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'pnpm' - - name: Install swagger-cli - run: npm i -g swagger-cli + - name: Install Redocly CLI + run: npm i -g @redocly/cli - run: corepack enable - run: pnpm i --frozen-lockfile - name: Check pnpm-lock.yaml @@ -43,4 +43,4 @@ jobs: - name: Build and generate run: pnpm build && pnpm --filter backend generate-api-json - name: Validation - run: swagger-cli validate ./packages/backend/built/api.json + run: npx @redocly/cli lint --extends=minimal ./packages/backend/built/api.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 381d2accd..65e34266d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ ### Client - Feat: 新しいゲームを追加 +- Feat: 絵文字の詳細ダイアログを追加 +- Feat: 枠線をつけるMFM`$[border.width=1,style=solid,color=fff,radius=0 ...]`を追加 - Enhance: ハッシュタグ入力時に、本文の末尾の行に何も書かれていない場合は新たにスペースを追加しないように - Enhance: チャンネルノートのピン留めをノートのメニューからできるように - Enhance: 管理者の場合はAPI tokenの発行画面で管理機能に関する権限を付与できるように @@ -35,7 +37,10 @@ - Enhance: 連合先のレートリミットに引っかかった際にリトライするようになりました - Enhance: ActivityPub Deliver queueでBodyを事前処理するように (#12916) - Enhance: クリップをエクスポートできるように +- Enhance: `api.json`のOpenAPI Specificationを3.1.0に更新 - Fix: `drive/files/update`でファイル名のバリデーションが機能していない問題を修正 +- Fix: `notes/create`で、`text`が空白文字のみで構成されているか`null`であって、かつ`text`だけであるリクエストに対するレスポンスが400になるように変更 +- Fix: `notes/create`で、`text`が空白文字のみで構成されていてかつリノート、ファイルまたは投票を含んでいるリクエストに対するレスポンスの`text`が`""`から`null`になるように変更 ## 2023.12.2 diff --git a/locales/index.d.ts b/locales/index.d.ts index 92df106ff..9d97f9f0c 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1207,6 +1207,8 @@ export interface Locale { "replay": string; "replaying": string; "ranking": string; + "lastNDays": string; + "backToTitle": string; "abuseReportCategory": string; "selectCategory": string; "reportComplete": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index d62d4a3fe..ca4755a8b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1204,6 +1204,8 @@ showReplay: "リプレイを見る" replay: "リプレイ" replaying: "リプレイ中" ranking: "ランキング" +lastNDays: "直近{n}日" +backToTitle: "タイトルへ" abuseReportCategory: "通報の種類" selectCategory: "カテゴリを選択" reportComplete: "通報完了" diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 1a0e72748..1b59bd627 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -331,6 +331,9 @@ export class NoteCreateService implements OnApplicationShutdown { data.text = data.text.slice(0, DB_MAX_NOTE_TEXT_LENGTH); } data.text = data.text.trim(); + if (data.text === '') { + data.text = null; + } } else { data.text = null; } diff --git a/packages/backend/src/server/api/endpoints/drive/files.ts b/packages/backend/src/server/api/endpoints/drive/files.ts index 6ba9722d4..f60be3e01 100644 --- a/packages/backend/src/server/api/endpoints/drive/files.ts +++ b/packages/backend/src/server/api/endpoints/drive/files.ts @@ -36,7 +36,7 @@ export const paramDef = { untilId: { type: 'string', format: 'misskey:id' }, folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) }, - sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size'] }, + sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size', null] }, }, required: [], } as const; diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index e5a90715f..457309731 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -60,6 +60,7 @@ export const paramDef = { '-firstRetrievedAt', '+latestRequestReceivedAt', '-latestRequestReceivedAt', + null, ], }, }, diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts index d248d62d8..af8022c7d 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/register-key.ts @@ -109,13 +109,13 @@ export const meta = { items: { type: 'string', enum: [ - "ble", - "cable", - "hybrid", - "internal", - "nfc", - "smart-card", - "usb", + 'ble', + 'cable', + 'hybrid', + 'internal', + 'nfc', + 'smart-card', + 'usb', ], }, }, @@ -129,8 +129,8 @@ export const meta = { authenticatorAttachment: { type: 'string', enum: [ - "cross-platform", - "platform", + 'cross-platform', + 'platform', ], }, requireResidentKey: { @@ -139,9 +139,9 @@ export const meta = { userVerification: { type: 'string', enum: [ - "discouraged", - "preferred", - "required", + 'discouraged', + 'preferred', + 'required', ], }, }, @@ -150,10 +150,11 @@ export const meta = { type: 'string', nullable: true, enum: [ - "direct", - "enterprise", - "indirect", - "none", + 'direct', + 'enterprise', + 'indirect', + 'none', + null, ], }, extensions: { diff --git a/packages/backend/src/server/api/endpoints/notes/create.test.ts b/packages/backend/src/server/api/endpoints/notes/create.test.ts index 6086f99c9..3228bbd01 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.test.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.test.ts @@ -34,11 +34,10 @@ describe('api:notes/create', () => { .toBe(VALID); }); - // TODO - //test('null post', () => { - // expect(v({ text: null })) - // .toBe(INVALID); - //}); + test('null post', () => { + expect(v({ text: null })) + .toBe(INVALID); + }); test('0 characters post', () => { expect(v({ text: '' })) @@ -49,6 +48,11 @@ describe('api:notes/create', () => { expect(v({ text: await tooLong })) .toBe(INVALID); }); + + test('whitespace-only post', () => { + expect(v({ text: ' ' })) + .toBe(INVALID); + }); }); describe('cw', () => { diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index ea483b9b5..e54387f78 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -173,13 +173,33 @@ export const paramDef = { }, }, // (re)note with text, files and poll are optional - anyOf: [ - { required: ['text'] }, - { required: ['renoteId'] }, - { required: ['fileIds'] }, - { required: ['mediaIds'] }, - { required: ['poll'] }, - ], + if: { + properties: { + renoteId: { + type: 'null', + }, + fileIds: { + type: 'null', + }, + mediaIds: { + type: 'null', + }, + poll: { + type: 'null', + }, + }, + }, + then: { + properties: { + text: { + type: 'string', + minLength: 1, + maxLength: MAX_NOTE_TEXT_LENGTH, + pattern: '[^\\s]+', + }, + }, + required: ['text'], + }, } as const; @Injectable() diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 0e71510b4..971a6116b 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -10,7 +10,7 @@ import { schemas, convertSchemaToOpenApiSchema } from './schemas.js'; export function genOpenapiSpec(config: Config) { const spec = { - openapi: '3.0.0', + openapi: '3.1.0', info: { version: config.version, @@ -56,7 +56,7 @@ export function genOpenapiSpec(config: Config) { } } - const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res) : {}; + const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res') : {}; let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n'; @@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) { } const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json'; - const schema = { ...endpoint.params }; + const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param') }; if (endpoint.meta.requireFile) { schema.properties = { @@ -210,7 +210,9 @@ export function genOpenapiSpec(config: Config) { }; spec.paths['/' + endpoint.name] = { - ...(endpoint.meta.allowGet ? { get: info } : {}), + ...(endpoint.meta.allowGet ? { + get: info, + } : {}), post: info, }; } diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index 2716f5f16..a862a7b74 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -6,32 +6,35 @@ import type { Schema } from '@/misc/json-schema.js'; import { refs } from '@/misc/json-schema.js'; -export function convertSchemaToOpenApiSchema(schema: Schema) { - // optional, refはスキーマ定義に含まれないので分離しておく +export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res') { + // optional, nullable, refはスキーマ定義に含まれないので分離しておく // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { optional, ref, ...res }: any = schema; + const { optional, nullable, ref, ...res }: any = schema; if (schema.type === 'object' && schema.properties) { - const required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); - if (required.length > 0) { + if (type === 'res') { + const required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); + if (required.length > 0) { // 空配列は許可されない - res.required = required; + res.required = required; + } } for (const k of Object.keys(schema.properties)) { - res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]); + res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type); } } if (schema.type === 'array' && schema.items) { - res.items = convertSchemaToOpenApiSchema(schema.items); + res.items = convertSchemaToOpenApiSchema(schema.items, type); } - if (schema.anyOf) res.anyOf = schema.anyOf.map(convertSchemaToOpenApiSchema); - if (schema.oneOf) res.oneOf = schema.oneOf.map(convertSchemaToOpenApiSchema); - if (schema.allOf) res.allOf = schema.allOf.map(convertSchemaToOpenApiSchema); + for (const o of ['anyOf', 'oneOf', 'allOf'] as const) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type)); + } - if (schema.ref) { + if (type === 'res' && schema.ref) { const $ref = `#/components/schemas/${schema.ref}`; if (schema.nullable || schema.optional) { res.allOf = [{ $ref }]; @@ -40,6 +43,14 @@ export function convertSchemaToOpenApiSchema(schema: Schema) { } } + if (schema.nullable) { + if (Array.isArray(schema.type) && !schema.type.includes('null')) { + res.type.push('null'); + } else if (typeof schema.type === 'string') { + res.type = [res.type, 'null']; + } + } + return res; } @@ -72,6 +83,6 @@ export const schemas = { }, ...Object.fromEntries( - Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema)]), + Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]), ), }; diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts index 11b1fc943..1567f8c8c 100644 --- a/packages/backend/test/e2e/note.ts +++ b/packages/backend/test/e2e/note.ts @@ -136,6 +136,19 @@ describe('Note', () => { assert.strictEqual(res.body.createdNote.renote.text, bobPost.text); }); + test('引用renoteで空白文字のみで構成されたtextにするとレスポンスがtext: nullになる', async () => { + const bobPost = await post(bob, { + text: 'test', + }); + const res = await api('/notes/create', { + text: ' ', + renoteId: bobPost.id, + }, alice); + + assert.strictEqual(res.status, 200); + assert.strictEqual(res.body.createdNote.text, null); + }); + test('visibility: followersでrenoteできる', async () => { const createRes = await api('/notes/create', { text: 'test', diff --git a/packages/frontend/assets/drop-and-fusion/poi1.mp3 b/packages/frontend/assets/drop-and-fusion/collision.mp3 similarity index 100% rename from packages/frontend/assets/drop-and-fusion/poi1.mp3 rename to packages/frontend/assets/drop-and-fusion/collision.mp3 diff --git a/packages/frontend/assets/drop-and-fusion/collision_yen.mp3 b/packages/frontend/assets/drop-and-fusion/collision_yen.mp3 new file mode 100644 index 000000000..6737357f6 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/collision_yen.mp3 differ diff --git a/packages/frontend/assets/drop-and-fusion/poi2.mp3 b/packages/frontend/assets/drop-and-fusion/drop.mp3 similarity index 100% rename from packages/frontend/assets/drop-and-fusion/poi2.mp3 rename to packages/frontend/assets/drop-and-fusion/drop.mp3 diff --git a/packages/frontend/assets/drop-and-fusion/drop_yen.mp3 b/packages/frontend/assets/drop-and-fusion/drop_yen.mp3 new file mode 100644 index 000000000..bbf385f15 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/drop_yen.mp3 differ diff --git a/packages/frontend/assets/drop-and-fusion/bubble2.mp3 b/packages/frontend/assets/drop-and-fusion/fusion.mp3 similarity index 100% rename from packages/frontend/assets/drop-and-fusion/bubble2.mp3 rename to packages/frontend/assets/drop-and-fusion/fusion.mp3 diff --git a/packages/frontend/assets/drop-and-fusion/fusion_yen.mp3 b/packages/frontend/assets/drop-and-fusion/fusion_yen.mp3 new file mode 100644 index 000000000..e8d203fb5 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/fusion_yen.mp3 differ diff --git a/packages/frontend/assets/drop-and-fusion/gameover_yen.mp3 b/packages/frontend/assets/drop-and-fusion/gameover_yen.mp3 new file mode 100644 index 000000000..c7fdcb5c8 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/gameover_yen.mp3 differ diff --git a/packages/frontend/assets/drop-and-fusion/go.png b/packages/frontend/assets/drop-and-fusion/go.png new file mode 100644 index 000000000..37468f139 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/go.png differ diff --git a/packages/frontend/assets/drop-and-fusion/cold_face.png b/packages/frontend/assets/drop-and-fusion/normal_monos/cold_face.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/cold_face.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/cold_face.png diff --git a/packages/frontend/assets/drop-and-fusion/exploding_head.png b/packages/frontend/assets/drop-and-fusion/normal_monos/exploding_head.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/exploding_head.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/exploding_head.png diff --git a/packages/frontend/assets/drop-and-fusion/face_with_open_mouth.png b/packages/frontend/assets/drop-and-fusion/normal_monos/face_with_open_mouth.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/face_with_open_mouth.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/face_with_open_mouth.png diff --git a/packages/frontend/assets/drop-and-fusion/face_with_symbols_on_mouth.png b/packages/frontend/assets/drop-and-fusion/normal_monos/face_with_symbols_on_mouth.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/face_with_symbols_on_mouth.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/face_with_symbols_on_mouth.png diff --git a/packages/frontend/assets/drop-and-fusion/grinning_squinting_face.png b/packages/frontend/assets/drop-and-fusion/normal_monos/grinning_squinting_face.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/grinning_squinting_face.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/grinning_squinting_face.png diff --git a/packages/frontend/assets/drop-and-fusion/heart_suit.png b/packages/frontend/assets/drop-and-fusion/normal_monos/heart_suit.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/heart_suit.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/heart_suit.png diff --git a/packages/frontend/assets/drop-and-fusion/pleading_face.png b/packages/frontend/assets/drop-and-fusion/normal_monos/pleading_face.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/pleading_face.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/pleading_face.png diff --git a/packages/frontend/assets/drop-and-fusion/smiling_face_with_hearts.png b/packages/frontend/assets/drop-and-fusion/normal_monos/smiling_face_with_hearts.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/smiling_face_with_hearts.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/smiling_face_with_hearts.png diff --git a/packages/frontend/assets/drop-and-fusion/smiling_face_with_sunglasses.png b/packages/frontend/assets/drop-and-fusion/normal_monos/smiling_face_with_sunglasses.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/smiling_face_with_sunglasses.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/smiling_face_with_sunglasses.png diff --git a/packages/frontend/assets/drop-and-fusion/zany_face.png b/packages/frontend/assets/drop-and-fusion/normal_monos/zany_face.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/zany_face.png rename to packages/frontend/assets/drop-and-fusion/normal_monos/zany_face.png diff --git a/packages/frontend/assets/drop-and-fusion/ready.png b/packages/frontend/assets/drop-and-fusion/ready.png new file mode 100644 index 000000000..10a87fcf5 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/ready.png differ diff --git a/packages/frontend/assets/drop-and-fusion/keycap_1.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_1.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_1.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_1.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_10.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_10.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_10.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_10.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_2.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_2.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_2.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_2.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_3.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_3.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_3.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_3.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_4.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_4.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_4.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_4.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_5.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_5.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_5.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_5.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_6.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_6.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_6.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_6.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_7.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_7.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_7.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_7.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_8.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_8.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_8.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_8.png diff --git a/packages/frontend/assets/drop-and-fusion/keycap_9.png b/packages/frontend/assets/drop-and-fusion/square_monos/keycap_9.png similarity index 100% rename from packages/frontend/assets/drop-and-fusion/keycap_9.png rename to packages/frontend/assets/drop-and-fusion/square_monos/keycap_9.png diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/candy_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/candy_color.svg new file mode 100644 index 000000000..6eab3ca49 --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/candy_color.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/chocolate_bar_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/chocolate_bar_color.svg new file mode 100644 index 000000000..eea5fec18 --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/chocolate_bar_color.svg @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/cookie_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/cookie_color.svg new file mode 100644 index 000000000..42b628cca --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/cookie_color.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/custard_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/custard_color.svg new file mode 100644 index 000000000..c76b3335e --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/custard_color.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/doughnut_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/doughnut_color.svg new file mode 100644 index 000000000..e8e225bc0 --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/doughnut_color.svg @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/lollipop_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/lollipop_color.svg new file mode 100644 index 000000000..ad90ac6f5 --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/lollipop_color.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/pancakes_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/pancakes_color.svg new file mode 100644 index 000000000..69ad069cc --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/pancakes_color.svg @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/shaved_ice_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/shaved_ice_color.svg new file mode 100644 index 000000000..64dfef8e0 --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/shaved_ice_color.svg @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/shortcake_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/shortcake_color.svg new file mode 100644 index 000000000..75143105d --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/shortcake_color.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/soft_ice_cream_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/soft_ice_cream_color.svg new file mode 100644 index 000000000..37be9c0cb --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/soft_ice_cream_color.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/verts/candy_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/verts/candy_color.svg new file mode 100644 index 000000000..e673f430f --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/verts/candy_color.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/sweets_monos/verts/custard_color.svg b/packages/frontend/assets/drop-and-fusion/sweets_monos/verts/custard_color.svg new file mode 100644 index 000000000..db547a5cf --- /dev/null +++ b/packages/frontend/assets/drop-and-fusion/sweets_monos/verts/custard_color.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/10000yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/10000yen.png new file mode 100644 index 000000000..bda777719 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/10000yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/1000yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/1000yen.png new file mode 100644 index 000000000..4c462fb1f Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/1000yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/100yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/100yen.png new file mode 100644 index 000000000..8911543af Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/100yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/10yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/10yen.png new file mode 100644 index 000000000..041f77389 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/10yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/1yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/1yen.png new file mode 100644 index 000000000..cc6dcfd74 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/1yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/2000yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/2000yen.png new file mode 100644 index 000000000..6048b7c99 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/2000yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/5000yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/5000yen.png new file mode 100644 index 000000000..b0fe26db1 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/5000yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/500yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/500yen.png new file mode 100644 index 000000000..9e3d2b766 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/500yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/50yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/50yen.png new file mode 100644 index 000000000..c8ef08997 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/50yen.png differ diff --git a/packages/frontend/assets/drop-and-fusion/yen_monos/5yen.png b/packages/frontend/assets/drop-and-fusion/yen_monos/5yen.png new file mode 100644 index 000000000..b120bdca3 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/yen_monos/5yen.png differ diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue new file mode 100644 index 000000000..c53bbca37 --- /dev/null +++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue @@ -0,0 +1,102 @@ + + + + + + + diff --git a/packages/frontend/src/components/MkHeatmap.vue b/packages/frontend/src/components/MkHeatmap.vue index f47b680f8..a77f3627f 100644 --- a/packages/frontend/src/components/MkHeatmap.vue +++ b/packages/frontend/src/components/MkHeatmap.vue @@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts index 650c79dff..f55069200 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts @@ -61,7 +61,12 @@ export default function(props: MfmProps, context: SetupContext) { if (t == null) return null; return t.match(/^[0-9.]+s$/) ? t : null; }; - + + const validColor = (c: string | null | undefined): string | null => { + if (c == null) return null; + return c.match(/^[0-9a-f]{3,6}$/i) ? c : null; + }; + const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm; /** @@ -240,17 +245,30 @@ export default function(props: MfmProps, context: SetupContext) { break; } case 'fg': { - let color = token.props.args.color; - if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; + let color = validColor(token.props.args.color); + color = color ?? 'f00'; style = `color: #${color}; overflow-wrap: anywhere;`; break; } case 'bg': { - let color = token.props.args.color; - if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; + let color = validColor(token.props.args.color); + color = color ?? 'f00'; style = `background-color: #${color}; overflow-wrap: anywhere;`; break; } + case 'border': { + let color = validColor(token.props.args.color); + color = color ? `#${color}` : 'var(--accent)'; + let b_style = token.props.args.style; + if ( + !['hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'] + .includes(b_style) + ) b_style = 'solid'; + const width = parseFloat(token.props.args.width ?? '1'); + const radius = parseFloat(token.props.args.radius ?? '0'); + style = `border: ${width}px ${b_style} ${color}; border-radius: ${radius}px`; + break; + } case 'ruby': { if (token.children.length === 1) { const child = token.children[0]; diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index 6e11987e7..2edaa0ee5 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -112,4 +112,4 @@ export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg'; export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg'; -export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime']; +export const MFM_TAGS = ['tada', 'jelly', 'twitch', 'shake', 'spin', 'jump', 'bounce', 'flip', 'x2', 'x3', 'x4', 'scale', 'position', 'fg', 'bg', 'border', 'font', 'blur', 'rainbow', 'sparkle', 'rotate', 'ruby', 'unixtime']; diff --git a/packages/frontend/src/pages/drop-and-fusion.game.vue b/packages/frontend/src/pages/drop-and-fusion.game.vue index c222fdeb4..f14f5dbff 100644 --- a/packages/frontend/src/pages/drop-and-fusion.game.vue +++ b/packages/frontend/src/pages/drop-and-fusion.game.vue @@ -4,19 +4,33 @@ SPDX-License-Identifier: AGPL-3.0-only -->