mirror of
https://github.com/misskey-dev/misskey.git
synced 2025-12-28 06:54:10 +00:00
Merge pull request #16972 from misskey-dev/develop
Some checks failed
API report (misskey.js) / report (push) Has been cancelled
Check SPDX-License-Identifier / check-spdx-license-id (push) Has been cancelled
Check copyright year / check_copyright_year (push) Has been cancelled
Dockle / dockle (push) Has been cancelled
Lint / pnpm_install (push) Has been cancelled
Lint / locale_verify (push) Has been cancelled
Storybook / build (push) Has been cancelled
Test (frontend) / Unit tests (frontend) (push) Has been cancelled
Test (frontend) / E2E tests (frontend) (chrome) (push) Has been cancelled
Test (production install and build) / Production build (push) Has been cancelled
api.json validation / validate-api-json (push) Has been cancelled
Lint / lint (backend) (push) Has been cancelled
Lint / lint (frontend) (push) Has been cancelled
Lint / lint (frontend-builder) (push) Has been cancelled
Lint / lint (frontend-embed) (push) Has been cancelled
Lint / lint (frontend-shared) (push) Has been cancelled
Lint / lint (icons-subsetter) (push) Has been cancelled
Lint / lint (misskey-bubble-game) (push) Has been cancelled
Lint / lint (misskey-js) (push) Has been cancelled
Lint / lint (misskey-reversi) (push) Has been cancelled
Lint / lint (sw) (push) Has been cancelled
Lint / typecheck (backend) (push) Has been cancelled
Lint / typecheck (frontend) (push) Has been cancelled
Lint / typecheck (misskey-js) (push) Has been cancelled
Lint / typecheck (sw) (push) Has been cancelled
Some checks failed
API report (misskey.js) / report (push) Has been cancelled
Check SPDX-License-Identifier / check-spdx-license-id (push) Has been cancelled
Check copyright year / check_copyright_year (push) Has been cancelled
Dockle / dockle (push) Has been cancelled
Lint / pnpm_install (push) Has been cancelled
Lint / locale_verify (push) Has been cancelled
Storybook / build (push) Has been cancelled
Test (frontend) / Unit tests (frontend) (push) Has been cancelled
Test (frontend) / E2E tests (frontend) (chrome) (push) Has been cancelled
Test (production install and build) / Production build (push) Has been cancelled
api.json validation / validate-api-json (push) Has been cancelled
Lint / lint (backend) (push) Has been cancelled
Lint / lint (frontend) (push) Has been cancelled
Lint / lint (frontend-builder) (push) Has been cancelled
Lint / lint (frontend-embed) (push) Has been cancelled
Lint / lint (frontend-shared) (push) Has been cancelled
Lint / lint (icons-subsetter) (push) Has been cancelled
Lint / lint (misskey-bubble-game) (push) Has been cancelled
Lint / lint (misskey-js) (push) Has been cancelled
Lint / lint (misskey-reversi) (push) Has been cancelled
Lint / lint (sw) (push) Has been cancelled
Lint / typecheck (backend) (push) Has been cancelled
Lint / typecheck (frontend) (push) Has been cancelled
Lint / typecheck (misskey-js) (push) Has been cancelled
Lint / typecheck (sw) (push) Has been cancelled
Release: 2025.12.1
This commit is contained in:
commit
7420c10a58
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,3 +1,17 @@
|
||||
## 2025.12.1
|
||||
|
||||
### Client
|
||||
- Fix: 特定の条件下でMisskeyが起動せず空白のページが表示されることがある問題を軽減
|
||||
- Fix: 初回読み込み時などに、言語設定で不整合が発生することがある問題を修正
|
||||
- Fix: 削除されたノートのリノートが正しく動作されない問題を修正
|
||||
- Fix: チャンネルオーナーが削除済みの時にチャンネルのヘッダーメニューが表示されない不具合を修正
|
||||
- Fix: ドライブで登録日以外でソートする場合は月でグループ化して表示しないように
|
||||
- Fix: `null` を返す note_view_intrruptor プラグインが動作しない問題を修正
|
||||
|
||||
### Server
|
||||
- Fix: ジョブキューでSentryが有効にならない問題を修正
|
||||
|
||||
|
||||
## 2025.12.0
|
||||
|
||||
### Note
|
||||
|
||||
@ -21,7 +21,7 @@ services:
|
||||
env_file:
|
||||
- .config/docker.env
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
- ./db:/var/lib/postgresql
|
||||
healthcheck:
|
||||
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||
interval: 5s
|
||||
|
||||
@ -43,7 +43,7 @@ services:
|
||||
env_file:
|
||||
- .config/docker.env
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
- ./db:/var/lib/postgresql
|
||||
healthcheck:
|
||||
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||
interval: 5s
|
||||
|
||||
@ -83,6 +83,7 @@ files: "Dateien"
|
||||
download: "Herunterladen"
|
||||
driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Einige Inhalte, die diese Datei verwenden, werden auch verschwinden."
|
||||
unfollowConfirm: "Möchtest du {name} wirklich nicht mehr folgen?"
|
||||
rejectFollowRequestConfirm: "Möchtest du die Follow-Anfrage von {name} ablehnen?"
|
||||
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
|
||||
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
|
||||
lists: "Listen"
|
||||
@ -1018,6 +1019,7 @@ pushNotificationAlreadySubscribed: "Push-Benachrichtigungen sind bereits aktivie
|
||||
pushNotificationNotSupported: "Entweder dein Browser oder deine Instanz unterstützt Push-Benachrichtigungen nicht"
|
||||
sendPushNotificationReadMessage: "Push-Benachrichtigungen löschen, sobald sie gelesen wurden"
|
||||
sendPushNotificationReadMessageCaption: "Dies kann gegebenenfalls den Batterieverbrauch deines Gerätes erhöhen."
|
||||
pleaseAllowPushNotification: "Bitte erlauben Sie Benachrichtigungen in Ihrem Browser."
|
||||
windowMaximize: "Maximieren"
|
||||
windowMinimize: "Minimieren"
|
||||
windowRestore: "Wiederherstellen"
|
||||
@ -1054,6 +1056,7 @@ permissionDeniedError: "Aktion verweigert"
|
||||
permissionDeniedErrorDescription: "Dieses Benutzerkonto besitzt nicht die Berechtigung, um diese Aktion auszuführen."
|
||||
preset: "Vorlage"
|
||||
selectFromPresets: "Aus Vorlagen wählen"
|
||||
custom: "Benutzerdefiniert"
|
||||
achievements: "Errungenschaften"
|
||||
gotInvalidResponseError: "Ungültige Antwort des Servers"
|
||||
gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
|
||||
@ -1243,6 +1246,7 @@ releaseToRefresh: "Zum Aktualisieren loslassen"
|
||||
refreshing: "Wird aktualisiert..."
|
||||
pullDownToRefresh: "Zum Aktualisieren ziehen"
|
||||
useGroupedNotifications: "Benachrichtigungen gruppieren"
|
||||
emailVerificationFailedError: "Es gab ein Problem bei der Überprüfung Ihrer E-Mail-Adresse. Der Link ist möglicherweise abgelaufen."
|
||||
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
|
||||
doReaction: "Reagieren"
|
||||
code: "Code"
|
||||
@ -1370,7 +1374,12 @@ defaultImageCompressionLevel: "Standard-Bildkomprimierungsstufe"
|
||||
defaultImageCompressionLevel_description: "Ein niedrigerer Wert erhält die Bildqualität, erhöht aber die Dateigröße. <br>Höhere Werte reduzieren die Dateigröße, verringern aber die Bildqualität."
|
||||
inMinutes: "Minute(n)"
|
||||
inDays: "Tag(en)"
|
||||
safeModeEnabled: "Der abgesicherte Modus ist aktiviert."
|
||||
schedule: "Planen"
|
||||
scheduled: "Geplant"
|
||||
widgets: "Widgets"
|
||||
deviceInfo: "Geräteinformation"
|
||||
youAreAdmin: "Sie sind ein Administrator"
|
||||
presets: "Vorlage"
|
||||
_imageEditing:
|
||||
_vars:
|
||||
|
||||
@ -83,6 +83,8 @@ files: "Files"
|
||||
download: "Download"
|
||||
driveFileDeleteConfirm: "Are you sure you want to delete \"{name}\"? All notes with this file attached will also be deleted."
|
||||
unfollowConfirm: "Are you sure you want to unfollow {name}?"
|
||||
cancelFollowRequestConfirm: "Are you sure that you want to cancel your follow request to {name}?"
|
||||
rejectFollowRequestConfirm: "Are you sure that you want to reject the follow request from {name}?"
|
||||
exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed."
|
||||
importRequested: "You've requested an import. This may take a while."
|
||||
lists: "Lists"
|
||||
|
||||
@ -1252,7 +1252,7 @@ detachAll: "Quitar todo"
|
||||
angle: "Ángulo"
|
||||
flip: "Echar de un capirotazo"
|
||||
showAvatarDecorations: "Mostrar decoraciones de avatar"
|
||||
releaseToRefresh: "Soltar para recargar"
|
||||
releaseToRefresh: "Suelta para recargar"
|
||||
refreshing: "Recargando..."
|
||||
pullDownToRefresh: "Tira hacia abajo para recargar"
|
||||
useGroupedNotifications: "Mostrar notificaciones agrupadas"
|
||||
|
||||
@ -53,7 +53,7 @@ copyRemoteLink: "复制远程链接"
|
||||
copyLinkRenote: "复制转帖链接"
|
||||
delete: "删除"
|
||||
deleteAndEdit: "删除并编辑"
|
||||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回应、转发和回复也将被删除。"
|
||||
deleteAndEditConfirm: "要删除此帖并再次编辑吗?此帖下所有的回应、转发和回复也将被删除。"
|
||||
addToList: "添加至列表"
|
||||
addToAntenna: "添加到天线"
|
||||
sendMessage: "发送消息"
|
||||
@ -136,7 +136,7 @@ emojiPicker: "表情符号选择器"
|
||||
pinnedEmojisForReactionSettingDescription: "可以设置发表回应时置顶显示的表情符号"
|
||||
pinnedEmojisSettingDescription: "可以设置输入表情符号时置顶显示的表情符号"
|
||||
emojiPickerDisplay: "选择器显示设置"
|
||||
overwriteFromPinnedEmojisForReaction: "从「置顶(回应)」设置覆盖"
|
||||
overwriteFromPinnedEmojisForReaction: "使用「置顶(回应)」设置覆盖"
|
||||
overwriteFromPinnedEmojis: "从全局设置覆盖"
|
||||
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
|
||||
rememberNoteVisibility: "保存上次设置的可见性"
|
||||
@ -153,8 +153,8 @@ block: "拉黑"
|
||||
unblock: "取消拉黑"
|
||||
suspend: "冻结"
|
||||
unsuspend: "解除冻结"
|
||||
blockConfirm: "确定要拉黑吗?"
|
||||
unblockConfirm: "确定要取消拉黑吗?"
|
||||
blockConfirm: "确定要屏蔽吗?"
|
||||
unblockConfirm: "确定要取消屏蔽吗?"
|
||||
suspendConfirm: "要冻结吗?"
|
||||
unsuspendConfirm: "要解除冻结吗?"
|
||||
selectList: "选择列表"
|
||||
@ -174,7 +174,7 @@ emojiUrl: "emoji 地址"
|
||||
addEmoji: "添加表情符号"
|
||||
settingGuide: "推荐配置"
|
||||
cacheRemoteFiles: "缓存远程文件"
|
||||
cacheRemoteFilesDescription: "启用此设定时,将在此服务器上缓存远程文件。虽然可以加快图片显示的速度,但是相对的会消耗大量的服务器存储空间。用户角色内的网盘容量决定了这个远程用户能在服务器上保留多少缓存。当超出了这个限制时,旧的文件将从缓存中被删除,成为链接。当禁用此设定时,则是从一开始就将远程文件保留为链接。此时推荐将 default.yml 的 proxyRemoteFiles 设置为 true 以优化缩略图生成及保护用户隐私。"
|
||||
cacheRemoteFilesDescription: "启用此设定时,将在此服务器上缓存远程文件。虽然可以加快图片显示的速度,但是相对的会消耗大量的服务器存储空间。用户角色内的网盘容量决定了这个远程用户能在服务器上保留多少缓存。当超出了这个限制时,旧的文件将从缓存中被删除,成为链接。当禁用此设定时,则是从一开始就将远程文件保留为链接。此时推荐将 的 proxyRemoteFiles 设置为 true 以优化缩略图生成及保护用户隐私。"
|
||||
youCanCleanRemoteFilesCache: "可以使用文件管理的🗑️按钮来删除所有的缓存。"
|
||||
cacheRemoteSensitiveFiles: "缓存远程敏感媒体文件"
|
||||
cacheRemoteSensitiveFilesDescription: "如果禁用这项设定,远程服务器的敏感媒体将不会被缓存,而是直接链接。"
|
||||
@ -184,7 +184,7 @@ flagAsCat: "喵!!!!!!!!!!!!"
|
||||
flagAsCatDescription: "喵喵喵??"
|
||||
flagShowTimelineReplies: "在时间线上显示帖子的回复"
|
||||
flagShowTimelineRepliesDescription: "启用时,时间线除了显示用户的帖子外,还会显示其他用户对帖子的回复。"
|
||||
autoAcceptFollowed: "自动允许来自我关注的用户对我的关注请求"
|
||||
autoAcceptFollowed: "自动允许回关请求"
|
||||
addAccount: "添加账户"
|
||||
reloadAccountsList: "更新账户列表"
|
||||
loginFailed: "登录失败"
|
||||
@ -247,8 +247,8 @@ mediaSilencedInstancesDescription: "设置要隐藏媒体文件的服务器,
|
||||
federationAllowedHosts: "允许联合的服务器"
|
||||
federationAllowedHostsDescription: "设定允许联合的服务器,以换行分隔。"
|
||||
muteAndBlock: "屏蔽/拉黑"
|
||||
mutedUsers: "已屏蔽用户"
|
||||
blockedUsers: "已拉黑的用户"
|
||||
mutedUsers: "已静音的用户"
|
||||
blockedUsers: "已屏蔽的用户"
|
||||
noUsers: "无用户"
|
||||
editProfile: "编辑资料"
|
||||
noteDeleteConfirm: "确定要删除该帖子吗?"
|
||||
@ -1344,7 +1344,7 @@ skip: "跳过"
|
||||
restore: "恢复"
|
||||
syncBetweenDevices: "设备间同步"
|
||||
preferenceSyncConflictTitle: "服务器上已存在设定值"
|
||||
preferenceSyncConflictText: "服务器上已有此设置的设定值。要覆盖哪个设定值?"
|
||||
preferenceSyncConflictText: "即将保存设定值到服务器,但检测到服务器上已有此设置的设定值。要使用哪个设定值?"
|
||||
preferenceSyncConflictChoiceMerge: "合并"
|
||||
preferenceSyncConflictChoiceServer: "服务器上的设定值"
|
||||
preferenceSyncConflictChoiceDevice: "设备上的设定值"
|
||||
@ -3270,7 +3270,7 @@ _watermarkEditor:
|
||||
driveFileTypeWarn: "不支持此文件"
|
||||
driveFileTypeWarnDescription: "请选择图像文件"
|
||||
title: "编辑水印"
|
||||
cover: "覆盖全体"
|
||||
cover: "覆盖所有"
|
||||
repeat: "平铺"
|
||||
preserveBoundingRect: "调整为旋转时不超出范围"
|
||||
opacity: "不透明度"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"version": "2025.12.0",
|
||||
"version": "2025.12.1",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -60,8 +60,6 @@
|
||||
"cssnano": "7.1.2",
|
||||
"esbuild": "0.27.0",
|
||||
"execa": "9.6.0",
|
||||
"fast-glob": "3.3.3",
|
||||
"glob": "13.0.0",
|
||||
"ignore-walk": "8.0.0",
|
||||
"js-yaml": "4.1.1",
|
||||
"postcss": "8.5.6",
|
||||
|
||||
@ -75,7 +75,6 @@
|
||||
"@aws-sdk/lib-storage": "3.940.0",
|
||||
"@discordapp/twemoji": "16.0.1",
|
||||
"@fastify/accepts": "5.0.3",
|
||||
"@fastify/cookie": "11.0.2",
|
||||
"@fastify/cors": "11.1.0",
|
||||
"@fastify/express": "4.0.2",
|
||||
"@fastify/http-proxy": "11.3.0",
|
||||
@ -107,7 +106,6 @@
|
||||
"body-parser": "2.2.1",
|
||||
"bullmq": "5.65.0",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"cbor": "10.0.11",
|
||||
"chalk": "5.6.2",
|
||||
"chalk-template": "1.1.2",
|
||||
"chokidar": "4.0.3",
|
||||
@ -131,7 +129,6 @@
|
||||
"is-svg": "6.1.0",
|
||||
"json5": "2.2.3",
|
||||
"jsonld": "9.0.0",
|
||||
"jsrsasign": "11.1.0",
|
||||
"juice": "11.0.3",
|
||||
"meilisearch": "0.54.0",
|
||||
"mfm-js": "0.25.0",
|
||||
@ -145,7 +142,6 @@
|
||||
"node-html-parser": "7.0.1",
|
||||
"nodemailer": "7.0.11",
|
||||
"nsfwjs": "4.2.0",
|
||||
"oauth": "0.10.2",
|
||||
"oauth2orize": "1.12.0",
|
||||
"oauth2orize-pkce": "0.1.2",
|
||||
"os-utils": "0.0.14",
|
||||
@ -174,7 +170,6 @@
|
||||
"tinycolor2": "1.6.0",
|
||||
"tmp": "0.2.5",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typeorm": "0.3.27",
|
||||
"typescript": "5.9.3",
|
||||
"ulid": "3.0.1",
|
||||
@ -199,12 +194,10 @@
|
||||
"@types/http-link-header": "1.0.7",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/jsonld": "1.5.15",
|
||||
"@types/jsrsasign": "10.5.15",
|
||||
"@types/mime-types": "3.0.1",
|
||||
"@types/ms": "2.1.0",
|
||||
"@types/node": "24.10.1",
|
||||
"@types/nodemailer": "7.0.4",
|
||||
"@types/oauth": "0.9.6",
|
||||
"@types/oauth2orize": "1.11.5",
|
||||
"@types/oauth2orize-pkce": "0.1.2",
|
||||
"@types/pg": "8.15.6",
|
||||
@ -225,13 +218,13 @@
|
||||
"@typescript-eslint/eslint-plugin": "8.48.0",
|
||||
"@typescript-eslint/parser": "8.48.0",
|
||||
"aws-sdk-client-mock": "4.1.0",
|
||||
"cbor": "10.0.11",
|
||||
"cross-env": "10.1.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"execa": "9.6.0",
|
||||
"fkill": "10.0.1",
|
||||
"jest": "29.7.0",
|
||||
"jest-mock": "29.7.0",
|
||||
"jest-util": "29.7.0",
|
||||
"js-yaml": "4.1.1",
|
||||
"nodemon": "3.1.11",
|
||||
"pid-port": "2.0.0",
|
||||
|
||||
@ -157,7 +157,7 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||
}
|
||||
|
||||
let Sentry: typeof import('@sentry/node') | undefined;
|
||||
if (Sentry != null) {
|
||||
if (this.config.sentryForBackend) {
|
||||
import('@sentry/node').then((mod) => {
|
||||
Sentry = mod;
|
||||
});
|
||||
|
||||
@ -50,7 +50,7 @@ services:
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./volumes/db.a
|
||||
target: /var/lib/postgresql/data
|
||||
target: /var/lib/postgresql
|
||||
bind:
|
||||
create_host_path: true
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ services:
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./volumes/db.b
|
||||
target: /var/lib/postgresql/data
|
||||
target: /var/lib/postgresql
|
||||
bind:
|
||||
create_host_path: true
|
||||
|
||||
|
||||
@ -17,8 +17,6 @@
|
||||
"@rollup/pluginutils": "5.3.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@vitejs/plugin-vue": "6.0.2",
|
||||
"@vue/compiler-sfc": "3.5.25",
|
||||
"astring": "1.9.0",
|
||||
"buraha": "0.0.1",
|
||||
"estree-walker": "3.0.3",
|
||||
"frontend-shared": "workspace:*",
|
||||
@ -31,9 +29,6 @@
|
||||
"sass": "1.94.2",
|
||||
"shiki": "3.17.0",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3",
|
||||
"uuid": "13.0.0",
|
||||
"vite": "7.2.4",
|
||||
"vue": "3.5.25"
|
||||
@ -56,7 +51,6 @@
|
||||
"cross-env": "10.1.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-vue": "10.6.2",
|
||||
"fast-glob": "3.3.3",
|
||||
"happy-dom": "20.0.11",
|
||||
"intersection-observer": "0.12.2",
|
||||
"micromatch": "4.0.8",
|
||||
@ -65,6 +59,7 @@
|
||||
"prettier": "3.7.1",
|
||||
"start-server-and-test": "2.1.3",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vue-component-type-helpers": "3.1.5",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
|
||||
@ -70,6 +70,8 @@
|
||||
importAppScript();
|
||||
});
|
||||
}
|
||||
|
||||
localStorage.setItem('lang', lang);
|
||||
//#endregion
|
||||
|
||||
async function addStyle(styleText) {
|
||||
|
||||
@ -3,14 +3,13 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import * as esbuild from 'esbuild';
|
||||
import { build } from 'esbuild';
|
||||
import { globSync } from 'glob';
|
||||
import { execa } from 'execa';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||
|
||||
const entryPoints = globSync('./js/**/**.{ts,tsx}');
|
||||
const entryPoints = fs.globSync('./js/**/**.{ts,tsx}');
|
||||
|
||||
/** @type {import('esbuild').BuildOptions} */
|
||||
const options = {
|
||||
|
||||
@ -3,12 +3,11 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { existsSync, readFileSync, globSync } from 'node:fs';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { basename, dirname } from 'node:path/posix';
|
||||
import { GENERATOR, type State, generate } from 'astring';
|
||||
import type * as estree from 'estree';
|
||||
import glob from 'fast-glob';
|
||||
import { format } from 'prettier';
|
||||
|
||||
interface SatisfiesExpression extends estree.BaseExpression {
|
||||
@ -439,38 +438,37 @@ function toStories(component: string): Promise<string> {
|
||||
|
||||
// glob('src/{components,pages,ui,widgets}/**/*.vue')
|
||||
(async () => {
|
||||
const globs = await Promise.all([
|
||||
glob('src/components/global/Mk*.vue'),
|
||||
glob('src/components/global/RouterView.vue'),
|
||||
glob('src/components/MkAbuseReportWindow.vue'),
|
||||
glob('src/components/MkAccountMoved.vue'),
|
||||
glob('src/components/MkAchievements.vue'),
|
||||
glob('src/components/MkAnalogClock.vue'),
|
||||
glob('src/components/MkAnimBg.vue'),
|
||||
glob('src/components/MkAnnouncementDialog.vue'),
|
||||
glob('src/components/MkAntennaEditor.vue'),
|
||||
glob('src/components/MkAntennaEditorDialog.vue'),
|
||||
glob('src/components/MkAsUi.vue'),
|
||||
glob('src/components/MkAutocomplete.vue'),
|
||||
glob('src/components/MkAvatars.vue'),
|
||||
glob('src/components/Mk[B-E]*.vue'),
|
||||
glob('src/components/MkFlashPreview.vue'),
|
||||
glob('src/components/MkGalleryPostPreview.vue'),
|
||||
glob('src/components/MkSignupServerRules.vue'),
|
||||
glob('src/components/MkUserSetupDialog.vue'),
|
||||
glob('src/components/MkUserSetupDialog.*.vue'),
|
||||
glob('src/components/MkImgPreviewDialog.vue'),
|
||||
glob('src/components/MkInstanceCardMini.vue'),
|
||||
glob('src/components/MkInviteCode.vue'),
|
||||
glob('src/components/MkTagItem.vue'),
|
||||
glob('src/components/MkRoleSelectDialog.vue'),
|
||||
glob('src/components/grid/MkGrid.vue'),
|
||||
glob('src/pages/admin/custom-emojis-manager2.vue'),
|
||||
glob('src/pages/admin/overview.ap-requests.vue'),
|
||||
glob('src/pages/user/home.vue'),
|
||||
glob('src/pages/search.vue'),
|
||||
]);
|
||||
const components = globs.flat();
|
||||
const components = [
|
||||
globSync('src/components/global/Mk*.vue'),
|
||||
globSync('src/components/global/RouterView.vue'),
|
||||
globSync('src/components/MkAbuseReportWindow.vue'),
|
||||
globSync('src/components/MkAccountMoved.vue'),
|
||||
globSync('src/components/MkAchievements.vue'),
|
||||
globSync('src/components/MkAnalogClock.vue'),
|
||||
globSync('src/components/MkAnimBg.vue'),
|
||||
globSync('src/components/MkAnnouncementDialog.vue'),
|
||||
globSync('src/components/MkAntennaEditor.vue'),
|
||||
globSync('src/components/MkAntennaEditorDialog.vue'),
|
||||
globSync('src/components/MkAsUi.vue'),
|
||||
globSync('src/components/MkAutocomplete.vue'),
|
||||
globSync('src/components/MkAvatars.vue'),
|
||||
globSync('src/components/Mk[B-E]*.vue'),
|
||||
globSync('src/components/MkFlashPreview.vue'),
|
||||
globSync('src/components/MkGalleryPostPreview.vue'),
|
||||
globSync('src/components/MkSignupServerRules.vue'),
|
||||
globSync('src/components/MkUserSetupDialog.vue'),
|
||||
globSync('src/components/MkUserSetupDialog.*.vue'),
|
||||
globSync('src/components/MkImgPreviewDialog.vue'),
|
||||
globSync('src/components/MkInstanceCardMini.vue'),
|
||||
globSync('src/components/MkInviteCode.vue'),
|
||||
globSync('src/components/MkTagItem.vue'),
|
||||
globSync('src/components/MkRoleSelectDialog.vue'),
|
||||
globSync('src/components/grid/MkGrid.vue'),
|
||||
globSync('src/pages/admin/custom-emojis-manager2.vue'),
|
||||
globSync('src/pages/admin/overview.ap-requests.vue'),
|
||||
globSync('src/pages/user/home.vue'),
|
||||
globSync('src/pages/search.vue'),
|
||||
].flat();
|
||||
await Promise.all(components.map(async (component) => {
|
||||
const stories = component.replace(/\.vue$/, '.stories.ts');
|
||||
await writeFile(stories, await toStories(component));
|
||||
|
||||
@ -16,7 +16,6 @@ import {
|
||||
type PluginOption
|
||||
} from 'vite';
|
||||
import fs from 'node:fs';
|
||||
import { glob } from 'glob';
|
||||
import JSON5 from 'json5';
|
||||
import MagicString, { SourceMap } from 'magic-string';
|
||||
import path from 'node:path'
|
||||
@ -724,7 +723,7 @@ export function pluginCreateSearchIndexVirtualModule(options: Options, asigner:
|
||||
|
||||
async load(id) {
|
||||
if (id == '\0' + allSearchIndexFile) {
|
||||
const files = await Promise.all(options.targetFilePaths.map(async (filePathPattern) => await glob(filePathPattern))).then(paths => paths.flat());
|
||||
const files = options.targetFilePaths.map((filePathPattern) => fs.globSync(filePathPattern)).flat();
|
||||
let generatedFile = '';
|
||||
let arrayElements = '';
|
||||
for (let file of files) {
|
||||
|
||||
@ -30,10 +30,8 @@
|
||||
"@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0",
|
||||
"@twemoji/parser": "16.0.0",
|
||||
"@vitejs/plugin-vue": "6.0.2",
|
||||
"@vue/compiler-sfc": "3.5.25",
|
||||
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15",
|
||||
"analytics": "0.8.19",
|
||||
"astring": "1.9.0",
|
||||
"broadcast-channel": "7.2.0",
|
||||
"buraha": "0.0.1",
|
||||
"canvas-confetti": "1.9.4",
|
||||
@ -46,7 +44,6 @@
|
||||
"compare-versions": "6.1.1",
|
||||
"cropperjs": "2.1.0",
|
||||
"date-fns": "4.1.0",
|
||||
"estree-walker": "3.0.3",
|
||||
"eventemitter3": "5.0.1",
|
||||
"execa": "9.6.0",
|
||||
"exifreader": "4.32.0",
|
||||
@ -57,7 +54,6 @@
|
||||
"ios-haptics": "0.1.4",
|
||||
"is-file-animated": "1.0.2",
|
||||
"json5": "2.2.3",
|
||||
"magic-string": "0.30.21",
|
||||
"matter-js": "0.20.0",
|
||||
"mediabunny": "1.25.3",
|
||||
"mfm-js": "0.25.0",
|
||||
@ -72,14 +68,10 @@
|
||||
"sanitize-html": "2.17.0",
|
||||
"sass": "1.94.2",
|
||||
"shiki": "3.17.0",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.181.2",
|
||||
"throttle-debounce": "5.0.2",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.16",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3",
|
||||
"v-code-diff": "1.13.1",
|
||||
"vite": "7.2.4",
|
||||
"vue": "3.5.25",
|
||||
@ -117,20 +109,20 @@
|
||||
"@types/seedrandom": "3.0.8",
|
||||
"@types/throttle-debounce": "5.0.2",
|
||||
"@types/tinycolor2": "1.4.6",
|
||||
"@types/ws": "8.18.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.48.0",
|
||||
"@typescript-eslint/parser": "8.48.0",
|
||||
"@vitest/coverage-v8": "4.0.14",
|
||||
"@vue/compiler-core": "3.5.25",
|
||||
"@vue/runtime-core": "3.5.25",
|
||||
"acorn": "8.15.0",
|
||||
"astring": "1.9.0",
|
||||
"cross-env": "10.1.0",
|
||||
"cypress": "15.7.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-vue": "10.6.2",
|
||||
"fast-glob": "3.3.3",
|
||||
"estree-walker": "3.0.3",
|
||||
"happy-dom": "20.0.11",
|
||||
"intersection-observer": "0.12.2",
|
||||
"magic-string": "0.30.21",
|
||||
"micromatch": "4.0.8",
|
||||
"minimatch": "10.1.1",
|
||||
"msw": "2.12.3",
|
||||
@ -144,6 +136,7 @@
|
||||
"storybook": "10.1.0",
|
||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-glsl": "1.5.4",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
"vitest": "4.0.14",
|
||||
|
||||
@ -42,6 +42,8 @@
|
||||
console.error('invalid lang value detected!!!', typeof lang, lang);
|
||||
lang = 'en-US';
|
||||
}
|
||||
|
||||
localStorage.setItem('lang', lang);
|
||||
//#endregion
|
||||
|
||||
//#region Script
|
||||
|
||||
@ -83,34 +83,58 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
<MkButton v-if="foldersPaginator.canFetchOlder.value" primary rounded @click="foldersPaginator.fetchOlder()">{{ i18n.ts.loadMore }}</MkButton>
|
||||
|
||||
<MkStickyContainer v-for="(item, i) in filesTimeline" :key="`${item.date.getFullYear()}/${item.date.getMonth() + 1}`">
|
||||
<template #header>
|
||||
<div :class="$style.date">
|
||||
<span><i class="ti ti-chevron-down"></i> {{ item.date.getFullYear() }}/{{ item.date.getMonth() + 1 }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="shouldBeGroupedByDate">
|
||||
<MkStickyContainer v-for="(item, i) in filesTimeline" :key="`${item.date.getFullYear()}/${item.date.getMonth() + 1}`">
|
||||
<template #header>
|
||||
<div :class="$style.date">
|
||||
<span><i class="ti ti-chevron-down"></i> {{ item.date.getFullYear() }}/{{ item.date.getMonth() + 1 }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<TransitionGroup
|
||||
tag="div"
|
||||
:enterActiveClass="prefer.s.animation ? $style.transition_files_enterActive : ''"
|
||||
:leaveActiveClass="prefer.s.animation ? $style.transition_files_leaveActive : ''"
|
||||
:enterFromClass="prefer.s.animation ? $style.transition_files_enterFrom : ''"
|
||||
:leaveToClass="prefer.s.animation ? $style.transition_files_leaveTo : ''"
|
||||
:moveClass="prefer.s.animation ? $style.transition_files_move : ''"
|
||||
:class="$style.files"
|
||||
>
|
||||
<XFile
|
||||
v-for="file in item.items" :key="file.id"
|
||||
:class="$style.file"
|
||||
:file="file"
|
||||
:folder="folder"
|
||||
:isSelected="selectedFiles.some(x => x.id === file.id)"
|
||||
@click="onFileClick($event, file)"
|
||||
@dragstart="onFileDragstart(file, $event)"
|
||||
@dragend="isDragSource = false"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
<TransitionGroup
|
||||
v-else
|
||||
tag="div"
|
||||
:enterActiveClass="prefer.s.animation ? $style.transition_files_enterActive : ''"
|
||||
:leaveActiveClass="prefer.s.animation ? $style.transition_files_leaveActive : ''"
|
||||
:enterFromClass="prefer.s.animation ? $style.transition_files_enterFrom : ''"
|
||||
:leaveToClass="prefer.s.animation ? $style.transition_files_leaveTo : ''"
|
||||
:moveClass="prefer.s.animation ? $style.transition_files_move : ''"
|
||||
:class="$style.files"
|
||||
>
|
||||
<XFile
|
||||
v-for="file in filesPaginator.items.value" :key="file.id"
|
||||
:class="$style.file"
|
||||
:file="file"
|
||||
:folder="folder"
|
||||
:isSelected="selectedFiles.some(x => x.id === file.id)"
|
||||
@click="onFileClick($event, file)"
|
||||
@dragstart="onFileDragstart(file, $event)"
|
||||
@dragend="isDragSource = false"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
|
||||
<TransitionGroup
|
||||
tag="div"
|
||||
:enterActiveClass="prefer.s.animation ? $style.transition_files_enterActive : ''"
|
||||
:leaveActiveClass="prefer.s.animation ? $style.transition_files_leaveActive : ''"
|
||||
:enterFromClass="prefer.s.animation ? $style.transition_files_enterFrom : ''"
|
||||
:leaveToClass="prefer.s.animation ? $style.transition_files_leaveTo : ''"
|
||||
:moveClass="prefer.s.animation ? $style.transition_files_move : ''"
|
||||
:class="$style.files"
|
||||
>
|
||||
<XFile
|
||||
v-for="file in item.items" :key="file.id"
|
||||
:class="$style.file"
|
||||
:file="file"
|
||||
:folder="folder"
|
||||
:isSelected="selectedFiles.some(x => x.id === file.id)"
|
||||
@click="onFileClick($event, file)"
|
||||
@dragstart="onFileDragstart(file, $event)"
|
||||
@dragend="isDragSource = false"
|
||||
/>
|
||||
</TransitionGroup>
|
||||
</MkStickyContainer>
|
||||
<MkButton v-show="filesPaginator.canFetchOlder.value" :class="$style.loadMore" primary rounded @click="filesPaginator.fetchOlder()">{{ i18n.ts.loadMore }}</MkButton>
|
||||
|
||||
<div v-if="filesPaginator.items.value.length == 0 && foldersPaginator.items.value.length == 0 && !fetching" :class="$style.empty">
|
||||
@ -217,6 +241,7 @@ const foldersPaginator = markRaw(new Paginator('drive/folders', {
|
||||
}));
|
||||
|
||||
const filesTimeline = makeDateGroupedTimelineComputedRef(filesPaginator.items, 'month');
|
||||
const shouldBeGroupedByDate = computed(() => ['+createdAt', '-createdAt'].includes(sortModeSelect.value));
|
||||
|
||||
watch(folder, () => emit('cd', folder.value));
|
||||
watch(sortModeSelect, () => {
|
||||
|
||||
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="!hardMuted && muted === false"
|
||||
v-if="!hardMuted && !hideByPlugin && muted === false"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
:class="[$style.root, { [$style.showActionsOnlyHover]: prefer.s.showNoteActionsOnlyHover, [$style.skipRender]: prefer.s.skipNoteRender }]"
|
||||
@ -38,7 +38,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<span v-if="note.channel" style="margin-left: 0.5em;" :title="note.channel.name"><i class="ti ti-device-tv"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
|
||||
<div v-if="isRenote && note.renote == null" :class="$style.deleted">
|
||||
{{ i18n.ts.deletedNote }}
|
||||
</div>
|
||||
<div v-else-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
|
||||
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
|
||||
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
|
||||
</div>
|
||||
@ -158,7 +161,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
|
||||
<div v-else-if="!hardMuted && !hideByPlugin" :class="$style.muted" @click="muted = false">
|
||||
<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
|
||||
<template #name>
|
||||
<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
|
||||
@ -267,6 +270,7 @@ let note = deepClone(props.note);
|
||||
|
||||
// plugin
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
const hideByPlugin = ref(false);
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
let result: Misskey.entities.Note | null = deepClone(note);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
@ -276,7 +280,11 @@ if (noteViewInterruptors.length > 0) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note = result as Misskey.entities.Note;
|
||||
if (result == null) {
|
||||
hideByPlugin.value = true;
|
||||
} else {
|
||||
note = result as Misskey.entities.Note;
|
||||
}
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note);
|
||||
@ -1144,4 +1152,14 @@ function emitUpdReaction(emoji: string, delta: number) {
|
||||
opacity: .8;
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.deleted {
|
||||
text-align: center;
|
||||
padding: 32px;
|
||||
margin: 6px 32px 28px;
|
||||
--color: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.15));
|
||||
background-size: auto auto;
|
||||
background-image: repeating-linear-gradient(135deg, transparent, transparent 10px, var(--color) 4px, var(--color) 14px);
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="!muted && !isDeleted"
|
||||
v-if="!muted && !hideByPlugin && !isDeleted"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
:class="$style.root"
|
||||
@ -43,178 +43,183 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<article :class="$style.note" @contextmenu.stop="onContextmenu">
|
||||
<header :class="$style.noteHeader">
|
||||
<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview/>
|
||||
<div :class="$style.noteHeaderBody">
|
||||
<div>
|
||||
<MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
|
||||
<MkUserName :nowrap="false" :user="appearNote.user"/>
|
||||
<div v-if="isRenote && note.renote == null" :class="$style.deleted">
|
||||
{{ i18n.ts.deletedNote }}
|
||||
</div>
|
||||
<template v-else>
|
||||
<article :class="$style.note" @contextmenu.stop="onContextmenu">
|
||||
<header :class="$style.noteHeader">
|
||||
<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview/>
|
||||
<div :class="$style.noteHeaderBody">
|
||||
<div>
|
||||
<MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
|
||||
<MkUserName :nowrap="false" :user="appearNote.user"/>
|
||||
</MkA>
|
||||
<span v-if="appearNote.user.isBot" :class="$style.isBot">bot</span>
|
||||
<div :class="$style.noteHeaderInfo">
|
||||
<span v-if="appearNote.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[appearNote.visibility]">
|
||||
<i v-if="appearNote.visibility === 'home'" class="ti ti-home"></i>
|
||||
<i v-else-if="appearNote.visibility === 'followers'" class="ti ti-lock"></i>
|
||||
<i v-else-if="appearNote.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
||||
</span>
|
||||
<span v-if="appearNote.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="$style.noteHeaderUsernameAndBadgeRoles">
|
||||
<div :class="$style.noteHeaderUsername">
|
||||
<MkAcct :user="appearNote.user"/>
|
||||
</div>
|
||||
<div v-if="appearNote.user.badgeRoles" :class="$style.noteHeaderBadgeRoles">
|
||||
<img v-for="(role, i) in appearNote.user.badgeRoles" :key="i" v-tooltip="role.name" :class="$style.noteHeaderBadgeRole" :src="role.iconUrl!"/>
|
||||
</div>
|
||||
</div>
|
||||
<MkInstanceTicker v-if="showTicker" :host="appearNote.user.host" :instance="appearNote.user.instance"/>
|
||||
</div>
|
||||
</header>
|
||||
<div :class="$style.noteContent">
|
||||
<p v-if="appearNote.cw != null" :class="$style.cw">
|
||||
<Mfm
|
||||
v-if="appearNote.cw != ''"
|
||||
:text="appearNote.cw"
|
||||
:author="appearNote.user"
|
||||
:nyaize="'respect'"
|
||||
:enableEmojiMenu="true"
|
||||
:enableEmojiMenuReaction="true"
|
||||
/>
|
||||
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
|
||||
</p>
|
||||
<div v-show="appearNote.cw == null || showContent">
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
||||
<MkA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
||||
<Mfm
|
||||
v-if="appearNote.text"
|
||||
:parsedNodes="parsed"
|
||||
:text="appearNote.text"
|
||||
:author="appearNote.user"
|
||||
:nyaize="'respect'"
|
||||
:emojiUrls="appearNote.emojis"
|
||||
:enableEmojiMenu="true"
|
||||
:enableEmojiMenuReaction="true"
|
||||
class="_selectable"
|
||||
/>
|
||||
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
|
||||
<div v-if="translating || translation" :class="$style.translation">
|
||||
<MkLoading v-if="translating" mini/>
|
||||
<div v-else-if="translation">
|
||||
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
|
||||
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" class="_selectable"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="appearNote.files && appearNote.files.length > 0">
|
||||
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
||||
</div>
|
||||
<MkPoll
|
||||
v-if="appearNote.poll"
|
||||
:noteId="appearNote.id"
|
||||
:multiple="appearNote.poll.multiple"
|
||||
:expiresAt="appearNote.poll.expiresAt"
|
||||
:choices="$appearNote.pollChoices"
|
||||
:author="appearNote.user"
|
||||
:emojiUrls="appearNote.emojis"
|
||||
:class="$style.poll"
|
||||
/>
|
||||
<div v-if="isEnabledUrlPreview">
|
||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
|
||||
</div>
|
||||
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
||||
</div>
|
||||
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
||||
</div>
|
||||
<footer>
|
||||
<div :class="$style.noteFooterInfo">
|
||||
<MkA :to="notePage(appearNote)">
|
||||
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
||||
</MkA>
|
||||
<span v-if="appearNote.user.isBot" :class="$style.isBot">bot</span>
|
||||
<div :class="$style.noteHeaderInfo">
|
||||
<span v-if="appearNote.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[appearNote.visibility]">
|
||||
<i v-if="appearNote.visibility === 'home'" class="ti ti-home"></i>
|
||||
<i v-else-if="appearNote.visibility === 'followers'" class="ti ti-lock"></i>
|
||||
<i v-else-if="appearNote.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
||||
</span>
|
||||
<span v-if="appearNote.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="$style.noteHeaderUsernameAndBadgeRoles">
|
||||
<div :class="$style.noteHeaderUsername">
|
||||
<MkAcct :user="appearNote.user"/>
|
||||
</div>
|
||||
<div v-if="appearNote.user.badgeRoles" :class="$style.noteHeaderBadgeRoles">
|
||||
<img v-for="(role, i) in appearNote.user.badgeRoles" :key="i" v-tooltip="role.name" :class="$style.noteHeaderBadgeRole" :src="role.iconUrl!"/>
|
||||
</div>
|
||||
</div>
|
||||
<MkInstanceTicker v-if="showTicker" :host="appearNote.user.host" :instance="appearNote.user.instance"/>
|
||||
</div>
|
||||
</header>
|
||||
<div :class="$style.noteContent">
|
||||
<p v-if="appearNote.cw != null" :class="$style.cw">
|
||||
<Mfm
|
||||
v-if="appearNote.cw != ''"
|
||||
:text="appearNote.cw"
|
||||
:author="appearNote.user"
|
||||
:nyaize="'respect'"
|
||||
:enableEmojiMenu="true"
|
||||
:enableEmojiMenuReaction="true"
|
||||
/>
|
||||
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
|
||||
</p>
|
||||
<div v-show="appearNote.cw == null || showContent">
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
||||
<MkA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
||||
<Mfm
|
||||
v-if="appearNote.text"
|
||||
:parsedNodes="parsed"
|
||||
:text="appearNote.text"
|
||||
:author="appearNote.user"
|
||||
:nyaize="'respect'"
|
||||
:emojiUrls="appearNote.emojis"
|
||||
:enableEmojiMenu="true"
|
||||
:enableEmojiMenuReaction="true"
|
||||
class="_selectable"
|
||||
/>
|
||||
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
|
||||
<div v-if="translating || translation" :class="$style.translation">
|
||||
<MkLoading v-if="translating" mini/>
|
||||
<div v-else-if="translation">
|
||||
<b>{{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: </b>
|
||||
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" class="_selectable"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="appearNote.files && appearNote.files.length > 0">
|
||||
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
||||
</div>
|
||||
<MkPoll
|
||||
v-if="appearNote.poll"
|
||||
<MkReactionsViewer
|
||||
v-if="appearNote.reactionAcceptance !== 'likeOnly'"
|
||||
style="margin-top: 6px;"
|
||||
:reactions="$appearNote.reactions"
|
||||
:reactionEmojis="$appearNote.reactionEmojis"
|
||||
:myReaction="$appearNote.myReaction"
|
||||
:noteId="appearNote.id"
|
||||
:multiple="appearNote.poll.multiple"
|
||||
:expiresAt="appearNote.poll.expiresAt"
|
||||
:choices="$appearNote.pollChoices"
|
||||
:author="appearNote.user"
|
||||
:emojiUrls="appearNote.emojis"
|
||||
:class="$style.poll"
|
||||
:maxNumber="16"
|
||||
@mockUpdateMyReaction="emitUpdReaction"
|
||||
/>
|
||||
<div v-if="isEnabledUrlPreview">
|
||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/>
|
||||
</div>
|
||||
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
||||
</div>
|
||||
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
||||
</div>
|
||||
<footer>
|
||||
<div :class="$style.noteFooterInfo">
|
||||
<MkA :to="notePage(appearNote)">
|
||||
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
||||
</MkA>
|
||||
</div>
|
||||
<MkReactionsViewer
|
||||
v-if="appearNote.reactionAcceptance !== 'likeOnly'"
|
||||
style="margin-top: 6px;"
|
||||
:reactions="$appearNote.reactions"
|
||||
:reactionEmojis="$appearNote.reactionEmojis"
|
||||
:myReaction="$appearNote.myReaction"
|
||||
:noteId="appearNote.id"
|
||||
:maxNumber="16"
|
||||
@mockUpdateMyReaction="emitUpdReaction"
|
||||
/>
|
||||
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
||||
<i class="ti ti-arrow-back-up"></i>
|
||||
<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.repliesCount) }}</p>
|
||||
</button>
|
||||
<button
|
||||
v-if="canRenote"
|
||||
ref="renoteButton"
|
||||
class="_button"
|
||||
:class="$style.noteFooterButton"
|
||||
@mousedown.prevent="renote()"
|
||||
>
|
||||
<i class="ti ti-repeat"></i>
|
||||
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p>
|
||||
</button>
|
||||
<button v-else class="_button" :class="$style.noteFooterButton" disabled>
|
||||
<i class="ti ti-ban"></i>
|
||||
</button>
|
||||
<button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()">
|
||||
<i v-if="appearNote.reactionAcceptance === 'likeOnly' && $appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--MI_THEME-love);"></i>
|
||||
<i v-else-if="$appearNote.myReaction != null" class="ti ti-minus" style="color: var(--MI_THEME-accent);"></i>
|
||||
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||
<i v-else class="ti ti-plus"></i>
|
||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || prefer.s.showReactionsCount) && $appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number($appearNote.reactionCount) }}</p>
|
||||
</button>
|
||||
<button v-if="prefer.s.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
|
||||
<i class="ti ti-paperclip"></i>
|
||||
</button>
|
||||
<button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="showMenu()">
|
||||
<i class="ti ti-dots"></i>
|
||||
</button>
|
||||
</footer>
|
||||
</article>
|
||||
<div :class="$style.tabs">
|
||||
<button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'replies' }]" @click="tab = 'replies'"><i class="ti ti-arrow-back-up"></i> {{ i18n.ts.replies }}</button>
|
||||
<button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'renotes' }]" @click="tab = 'renotes'"><i class="ti ti-repeat"></i> {{ i18n.ts.renotes }}</button>
|
||||
<button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'reactions' }]" @click="tab = 'reactions'"><i class="ti ti-icons"></i> {{ i18n.ts.reactions }}</button>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="tab === 'replies'">
|
||||
<div v-if="!repliesLoaded" style="padding: 16px">
|
||||
<MkButton style="margin: 0 auto;" primary rounded @click="loadReplies">{{ i18n.ts.loadReplies }}</MkButton>
|
||||
</div>
|
||||
<MkNoteSub v-for="note in replies" :key="note.id" :note="note" :class="$style.reply" :detail="true"/>
|
||||
</div>
|
||||
<div v-else-if="tab === 'renotes'" :class="$style.tab_renotes">
|
||||
<MkPagination :paginator="renotesPaginator">
|
||||
<template #default="{ items }">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); grid-gap: 12px;">
|
||||
<MkA v-for="item in items" :key="item.id" :to="userPage(item.user)">
|
||||
<MkUserCardMini :user="item.user" :withChart="false"/>
|
||||
</MkA>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
</div>
|
||||
<div v-else-if="tab === 'reactions'" :class="$style.tab_reactions">
|
||||
<div :class="$style.reactionTabs">
|
||||
<button v-for="reaction in Object.keys($appearNote.reactions)" :key="reaction" :class="[$style.reactionTab, { [$style.reactionTabActive]: reactionTabType === reaction }]" class="_button" @click="reactionTabType = reaction">
|
||||
<MkReactionIcon :reaction="reaction"/>
|
||||
<span style="margin-left: 4px;">{{ $appearNote.reactions[reaction] }}</span>
|
||||
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
||||
<i class="ti ti-arrow-back-up"></i>
|
||||
<p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.repliesCount) }}</p>
|
||||
</button>
|
||||
</div>
|
||||
<MkPagination v-if="reactionTabType" :key="reactionTabType" :paginator="reactionsPaginator">
|
||||
<template #default="{ items }">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); grid-gap: 12px;">
|
||||
<MkA v-for="item in items" :key="item.id" :to="userPage(item.user)">
|
||||
<MkUserCardMini :user="item.user" :withChart="false"/>
|
||||
</MkA>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
<button
|
||||
v-if="canRenote"
|
||||
ref="renoteButton"
|
||||
class="_button"
|
||||
:class="$style.noteFooterButton"
|
||||
@mousedown.prevent="renote()"
|
||||
>
|
||||
<i class="ti ti-repeat"></i>
|
||||
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p>
|
||||
</button>
|
||||
<button v-else class="_button" :class="$style.noteFooterButton" disabled>
|
||||
<i class="ti ti-ban"></i>
|
||||
</button>
|
||||
<button ref="reactButton" :class="$style.noteFooterButton" class="_button" @click="toggleReact()">
|
||||
<i v-if="appearNote.reactionAcceptance === 'likeOnly' && $appearNote.myReaction != null" class="ti ti-heart-filled" style="color: var(--MI_THEME-love);"></i>
|
||||
<i v-else-if="$appearNote.myReaction != null" class="ti ti-minus" style="color: var(--MI_THEME-accent);"></i>
|
||||
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||
<i v-else class="ti ti-plus"></i>
|
||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || prefer.s.showReactionsCount) && $appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number($appearNote.reactionCount) }}</p>
|
||||
</button>
|
||||
<button v-if="prefer.s.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
|
||||
<i class="ti ti-paperclip"></i>
|
||||
</button>
|
||||
<button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="showMenu()">
|
||||
<i class="ti ti-dots"></i>
|
||||
</button>
|
||||
</footer>
|
||||
</article>
|
||||
<div :class="$style.tabs">
|
||||
<button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'replies' }]" @click="tab = 'replies'"><i class="ti ti-arrow-back-up"></i> {{ i18n.ts.replies }}</button>
|
||||
<button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'renotes' }]" @click="tab = 'renotes'"><i class="ti ti-repeat"></i> {{ i18n.ts.renotes }}</button>
|
||||
<button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'reactions' }]" @click="tab = 'reactions'"><i class="ti ti-icons"></i> {{ i18n.ts.reactions }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="tab === 'replies'">
|
||||
<div v-if="!repliesLoaded" style="padding: 16px">
|
||||
<MkButton style="margin: 0 auto;" primary rounded @click="loadReplies">{{ i18n.ts.loadReplies }}</MkButton>
|
||||
</div>
|
||||
<MkNoteSub v-for="note in replies" :key="note.id" :note="note" :class="$style.reply" :detail="true"/>
|
||||
</div>
|
||||
<div v-else-if="tab === 'renotes'" :class="$style.tab_renotes">
|
||||
<MkPagination :paginator="renotesPaginator" :forceDisableInfiniteScroll="true">
|
||||
<template #default="{ items }">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); grid-gap: 12px;">
|
||||
<MkA v-for="item in items" :key="item.id" :to="userPage(item.user)">
|
||||
<MkUserCardMini :user="item.user" :withChart="false"/>
|
||||
</MkA>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
</div>
|
||||
<div v-else-if="tab === 'reactions'" :class="$style.tab_reactions">
|
||||
<div :class="$style.reactionTabs">
|
||||
<button v-for="reaction in Object.keys($appearNote.reactions)" :key="reaction" :class="[$style.reactionTab, { [$style.reactionTabActive]: reactionTabType === reaction }]" class="_button" @click="reactionTabType = reaction">
|
||||
<MkReactionIcon :reaction="reaction"/>
|
||||
<span style="margin-left: 4px;">{{ $appearNote.reactions[reaction] }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<MkPagination v-if="reactionTabType" :key="reactionTabType" :paginator="reactionsPaginator" :forceDisableInfiniteScroll="true">
|
||||
<template #default="{ items }">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); grid-gap: 12px;">
|
||||
<MkA v-for="item in items" :key="item.id" :to="userPage(item.user)">
|
||||
<MkUserCardMini :user="item.user" :withChart="false"/>
|
||||
</MkA>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else-if="muted" class="_panel" :class="$style.muted" @click="muted = false">
|
||||
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
||||
@ -289,6 +294,7 @@ let note = deepClone(props.note);
|
||||
|
||||
// plugin
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
const hideByPlugin = ref(false);
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
let result: Misskey.entities.Note | null = deepClone(note);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
@ -298,7 +304,11 @@ if (noteViewInterruptors.length > 0) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note = result as Misskey.entities.Note;
|
||||
if (result == null) {
|
||||
hideByPlugin.value = true;
|
||||
} else {
|
||||
note = result as Misskey.entities.Note;
|
||||
}
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note);
|
||||
@ -944,4 +954,14 @@ function loadConversation() {
|
||||
text-align: center;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.deleted {
|
||||
text-align: center;
|
||||
padding: 32px;
|
||||
margin: 6px 32px 32px;
|
||||
--color: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.15));
|
||||
background-size: auto auto;
|
||||
background-image: repeating-linear-gradient(135deg, transparent, transparent 10px, var(--color) 4px, var(--color) 14px);
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -77,7 +77,7 @@ export const components = {
|
||||
SearchIcon: SearchIcon,
|
||||
};
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
I18n: typeof I18n;
|
||||
RouterView: typeof RouterView;
|
||||
|
||||
@ -257,7 +257,7 @@ async function search() {
|
||||
}
|
||||
|
||||
const headerActions = computed(() => {
|
||||
if (channel.value && channel.value.userId) {
|
||||
if (channel.value) {
|
||||
const headerItems: PageHeaderItem[] = [];
|
||||
|
||||
headerItems.push({
|
||||
|
||||
@ -63,7 +63,7 @@ async function setAntenna() {
|
||||
})),
|
||||
} : undefined),
|
||||
],
|
||||
default: props.column.antennaId,
|
||||
default: antennas.find(x => x.id === props.column.antennaId)?.id,
|
||||
});
|
||||
|
||||
if (canceled || antennaIdOrOperation == null) return;
|
||||
|
||||
@ -63,7 +63,7 @@ async function setChannel() {
|
||||
items: channels.map(x => ({
|
||||
value: x.id, label: x.name,
|
||||
})),
|
||||
default: props.column.channelId,
|
||||
default: channels.find(x => x.id === props.column.channelId)?.id,
|
||||
});
|
||||
if (canceled || chosenChannelId == null) return;
|
||||
const chosenChannel = channels.find(x => x.id === chosenChannelId)!;
|
||||
|
||||
@ -70,7 +70,7 @@ async function setList() {
|
||||
})),
|
||||
} : undefined),
|
||||
],
|
||||
default: props.column.listId,
|
||||
default: lists.find(x => x.id === props.column.listId)?.id,
|
||||
});
|
||||
if (canceled || listIdOrOperation == null) return;
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ async function setRole() {
|
||||
items: roles.map(x => ({
|
||||
value: x.id, label: x.name,
|
||||
})),
|
||||
default: props.column.roleId,
|
||||
default: roles.find(x => x.id === props.column.roleId)?.id,
|
||||
});
|
||||
if (canceled || roleId == null) return;
|
||||
const role = roles.find(x => x.id === roleId)!;
|
||||
|
||||
@ -104,6 +104,7 @@ async function setType() {
|
||||
}, {
|
||||
value: 'global', label: i18n.ts._timelines.global,
|
||||
}],
|
||||
default: props.column.tl,
|
||||
});
|
||||
if (canceled) {
|
||||
if (props.column.tl == null) {
|
||||
|
||||
@ -10,7 +10,6 @@ import { watch as chokidarWatch } from 'chokidar';
|
||||
import * as esbuild from 'esbuild';
|
||||
import { build } from 'esbuild';
|
||||
import { execa } from 'execa';
|
||||
import { globSync } from 'glob';
|
||||
import { generateLocaleInterface } from './scripts/generateLocaleInterface.js';
|
||||
import type { BuildOptions, BuildResult, Plugin, PluginBuild } from 'esbuild';
|
||||
|
||||
@ -22,7 +21,7 @@ const _rootPackage = JSON.parse(fs.readFileSync(resolve(_rootPackageDir, 'packag
|
||||
const _frontendLocalesDir = resolve(_dirname, '../../built/_frontend_dist_/locales');
|
||||
const _localesDir = resolve(_rootPackageDir, 'locales');
|
||||
|
||||
const entryPoints = globSync('./src/**/**.{ts,tsx}');
|
||||
const entryPoints = fs.globSync('./src/**/**.{ts,tsx}');
|
||||
|
||||
const options: BuildOptions = {
|
||||
entryPoints,
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
"chokidar": "4.0.3",
|
||||
"esbuild": "0.27.0",
|
||||
"execa": "9.6.0",
|
||||
"glob": "11.1.0",
|
||||
"nodemon": "3.1.11",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3"
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
"dependencies": {
|
||||
"@tabler/icons-webfont": "3.35.0",
|
||||
"harfbuzzjs": "0.4.13",
|
||||
"tiny-glob": "0.2.9",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3",
|
||||
"wawoff2": "2.0.1"
|
||||
|
||||
@ -3,9 +3,8 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { promises as fsp, existsSync } from 'fs';
|
||||
import path from 'path';
|
||||
import glob from 'tiny-glob';
|
||||
import { promises as fsp, existsSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { generateSubsettedFont } from './subsetter.js';
|
||||
|
||||
const filesToScan = {
|
||||
@ -47,8 +46,8 @@ async function main() {
|
||||
const iconsToPack = new Set<string>();
|
||||
|
||||
const cwd = path.resolve(process.cwd(), '../../');
|
||||
const files = await glob(dir, { cwd });
|
||||
for (const file of files) {
|
||||
const files = fsp.glob(dir, { cwd });
|
||||
for await (const file of files) {
|
||||
//console.log(`Scanning ${file}`);
|
||||
const content = await fsp.readFile(path.resolve(cwd, file), 'utf-8');
|
||||
const classRegex = /ti-[a-z0-9-]+/g;
|
||||
|
||||
@ -3,14 +3,13 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import * as esbuild from 'esbuild';
|
||||
import { build } from 'esbuild';
|
||||
import { globSync } from 'glob';
|
||||
import { execa } from 'execa';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||
|
||||
const entryPoints = globSync('./src/**/**.{ts,tsx}');
|
||||
const entryPoints = fs.globSync('./src/**/**.{ts,tsx}');
|
||||
|
||||
/** @type {import('esbuild').BuildOptions} */
|
||||
const options = {
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
"@typescript-eslint/parser": "8.48.0",
|
||||
"esbuild": "0.27.0",
|
||||
"execa": "9.6.0",
|
||||
"glob": "11.1.0",
|
||||
"nodemon": "3.1.11",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
|
||||
@ -3,14 +3,13 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import * as esbuild from 'esbuild';
|
||||
import { build } from 'esbuild';
|
||||
import { globSync } from 'glob';
|
||||
import { execa } from 'execa';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||
|
||||
const entryPoints = globSync('./src/**/**.{ts,tsx}');
|
||||
const entryPoints = fs.globSync('./src/**/**.{ts,tsx}');
|
||||
|
||||
/** @type {import('esbuild').BuildOptions} */
|
||||
const options = {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "module",
|
||||
"name": "misskey-js",
|
||||
"version": "2025.12.0",
|
||||
"version": "2025.12.1",
|
||||
"description": "Misskey SDK for JavaScript",
|
||||
"license": "MIT",
|
||||
"main": "./built/index.js",
|
||||
@ -44,7 +44,6 @@
|
||||
"@vitest/coverage-v8": "4.0.13",
|
||||
"esbuild": "0.27.0",
|
||||
"execa": "9.6.0",
|
||||
"glob": "13.0.0",
|
||||
"ncp": "2.0.0",
|
||||
"nodemon": "3.1.11",
|
||||
"tsd": "0.33.0",
|
||||
|
||||
@ -3,14 +3,13 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import * as esbuild from 'esbuild';
|
||||
import { build } from 'esbuild';
|
||||
import { globSync } from 'glob';
|
||||
import { execa } from 'execa';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||
|
||||
const entryPoints = globSync('./src/**/**.{ts,tsx}');
|
||||
const entryPoints = fs.globSync('./src/**/**.{ts,tsx}');
|
||||
|
||||
/** @type {import('esbuild').BuildOptions} */
|
||||
const options = {
|
||||
|
||||
@ -29,7 +29,6 @@
|
||||
"@typescript-eslint/parser": "8.48.0",
|
||||
"esbuild": "0.27.0",
|
||||
"execa": "9.6.0",
|
||||
"glob": "11.1.0",
|
||||
"nodemon": "3.1.11",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
|
||||
6
packages/sw/src/const.ts
Normal file
6
packages/sw/src/const.ts
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export const FETCH_TIMEOUT_MS = 10000;
|
||||
@ -8,6 +8,7 @@
|
||||
*/
|
||||
import { get, set } from 'idb-keyval';
|
||||
import { I18n } from '@@/js/i18n.js';
|
||||
import { FETCH_TIMEOUT_MS } from '@/const.js';
|
||||
import type { Locale } from 'i18n';
|
||||
|
||||
class SwLang {
|
||||
@ -37,11 +38,21 @@ class SwLang {
|
||||
|
||||
// _DEV_がtrueの場合は常に最新化
|
||||
if (!localeRes || _DEV_) {
|
||||
localeRes = await fetch(localeUrl);
|
||||
const clone = localeRes.clone();
|
||||
if (!clone.clone().ok) throw new Error('locale fetching error');
|
||||
const controller = new AbortController();
|
||||
const timeout = globalThis.setTimeout(() => {
|
||||
controller.abort('locale-fetch-timeout');
|
||||
}, FETCH_TIMEOUT_MS);
|
||||
|
||||
caches.open(this.cacheName).then(cache => cache.put(localeUrl, clone));
|
||||
try {
|
||||
localeRes = await fetch(localeUrl, { signal: controller.signal });
|
||||
|
||||
const clone = localeRes.clone();
|
||||
if (!clone.clone().ok) throw new Error('locale fetching error');
|
||||
|
||||
caches.open(this.cacheName).then(cache => cache.put(localeUrl, clone));
|
||||
} finally {
|
||||
globalThis.clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
return new I18n<Locale>(await localeRes.json());
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
import { get } from 'idb-keyval';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { FETCH_TIMEOUT_MS } from '@/const.js';
|
||||
import type { PushNotificationDataMap } from '@/types.js';
|
||||
import type { I18n } from '@@/js/i18n.js';
|
||||
import type { Locale } from 'i18n';
|
||||
@ -12,8 +13,67 @@ import { createEmptyNotification, createNotification } from '@/scripts/create-no
|
||||
import { swLang } from '@/scripts/lang.js';
|
||||
import * as swos from '@/scripts/operations.js';
|
||||
|
||||
globalThis.addEventListener('install', () => {
|
||||
// ev.waitUntil(globalThis.skipWaiting());
|
||||
async function respondToNavigation(request: Request): Promise<Response> {
|
||||
const controller = new AbortController();
|
||||
const timeout = globalThis.setTimeout(() => {
|
||||
controller.abort('navigation-timeout');
|
||||
}, FETCH_TIMEOUT_MS);
|
||||
|
||||
try {
|
||||
const response = await fetch(request, { signal: controller.signal });
|
||||
|
||||
if (response?.status && response.status < 500) return response;
|
||||
if (response?.type === 'opaqueredirect') return response;
|
||||
} catch (error) {
|
||||
if (_DEV_) {
|
||||
console.warn('navigation fetch failed; showing offline page', error);
|
||||
}
|
||||
} finally {
|
||||
globalThis.clearTimeout(timeout);
|
||||
}
|
||||
|
||||
// Only show offline page when network request actually fails
|
||||
const html = await offlineContentHTML();
|
||||
return new Response(html, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'content-type': 'text/html',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function offlineContentHTML() {
|
||||
let i18n: Partial<I18n<Locale>>;
|
||||
try {
|
||||
i18n = await (swLang.i18n ?? await swLang.fetchLocale()) as Partial<I18n<Locale>>;
|
||||
} catch {
|
||||
i18n = {};
|
||||
}
|
||||
|
||||
const messages = {
|
||||
title: i18n.ts?._offlineScreen.title ?? 'Offline - Could not connect to server',
|
||||
header: i18n.ts?._offlineScreen.header ?? 'Could not connect to server',
|
||||
reload: i18n.ts?.reload ?? 'Reload',
|
||||
};
|
||||
|
||||
return `<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1"name="viewport"><title>${messages.title}</title><style>body{background-color:#0c1210;color:#dee7e4;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:24px;box-sizing:border-box}.icon{max-width:120px;width:100%;height:auto;margin-bottom:20px;}.message{text-align:center;font-size:20px;font-weight:700;margin-bottom:20px}.version{text-align:center;font-size:90%;margin-bottom:20px}button{padding:7px 14px;min-width:100px;font-weight:700;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;border-radius:99rem;background-color:#b4e900;color:#192320;border:none;cursor:pointer;-webkit-tap-highlight-color:transparent}button:hover{background-color:#c6ff03}</style></head><body><svg class="icon"fill="none"height="24"stroke="currentColor"stroke-linecap="round"stroke-linejoin="round"stroke-width="2"viewBox="0 0 24 24"width="24"xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z"fill="none"stroke="none"/><path d="M9.58 5.548c.24 -.11 .492 -.207 .752 -.286c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99c1.913 0 3.464 1.56 3.464 3.486c0 .957 -.383 1.824 -1.003 2.454m-2.997 1.033h-11.343c-2.572 -.004 -4.657 -2.011 -4.657 -4.487c0 -2.475 2.085 -4.482 4.657 -4.482c.13 -.582 .37 -1.128 .7 -1.62"/><path d="M3 3l18 18"/></svg><div class="message">${messages.header}</div><div class="version">v${_VERSION_}</div><button onclick="reloadPage()">${messages.reload}</button><script>function reloadPage(){location.reload(!0)}</script></body></html>`;
|
||||
}
|
||||
|
||||
globalThis.addEventListener('install', (ev) => {
|
||||
// 次の問題が発生するため、ServiceWorkerAutoPreload をオプトアウトする必要がある
|
||||
// https://issues.chromium.org/issues/466790291
|
||||
if ('addRoutes' in ev) {
|
||||
// doc: https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent/addRoutes
|
||||
// @ts-expect-error 実験的なAPIなので型定義がない
|
||||
ev.addRoutes({
|
||||
condition: {
|
||||
// doc: https://developer.mozilla.org/ja/docs/Web/API/URLPattern
|
||||
// @ts-expect-error 実験的なAPIなので型定義がない
|
||||
urlPattern: new URLPattern({}),
|
||||
},
|
||||
source: 'fetch-event',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
globalThis.addEventListener('activate', ev => {
|
||||
@ -28,17 +88,6 @@ globalThis.addEventListener('activate', ev => {
|
||||
);
|
||||
});
|
||||
|
||||
async function offlineContentHTML() {
|
||||
const i18n = await (swLang.i18n ?? swLang.fetchLocale()) as Partial<I18n<Locale>>;
|
||||
const messages = {
|
||||
title: i18n.ts?._offlineScreen.title ?? 'Offline - Could not connect to server',
|
||||
header: i18n.ts?._offlineScreen.header ?? 'Could not connect to server',
|
||||
reload: i18n.ts?.reload ?? 'Reload',
|
||||
};
|
||||
|
||||
return `<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1"name="viewport"><title>${messages.title}</title><style>body{background-color:#0c1210;color:#dee7e4;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:24px;box-sizing:border-box}.icon{max-width:120px;width:100%;height:auto;margin-bottom:20px;}.message{text-align:center;font-size:20px;font-weight:700;margin-bottom:20px}.version{text-align:center;font-size:90%;margin-bottom:20px}button{padding:7px 14px;min-width:100px;font-weight:700;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;border-radius:99rem;background-color:#b4e900;color:#192320;border:none;cursor:pointer;-webkit-tap-highlight-color:transparent}button:hover{background-color:#c6ff03}</style></head><body><svg class="icon"fill="none"height="24"stroke="currentColor"stroke-linecap="round"stroke-linejoin="round"stroke-width="2"viewBox="0 0 24 24"width="24"xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z"fill="none"stroke="none"/><path d="M9.58 5.548c.24 -.11 .492 -.207 .752 -.286c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99c1.913 0 3.464 1.56 3.464 3.486c0 .957 -.383 1.824 -1.003 2.454m-2.997 1.033h-11.343c-2.572 -.004 -4.657 -2.011 -4.657 -4.487c0 -2.475 2.085 -4.482 4.657 -4.482c.13 -.582 .37 -1.128 .7 -1.62"/><path d="M3 3l18 18"/></svg><div class="message">${messages.header}</div><div class="version">v${_VERSION_}</div><button onclick="reloadPage()">${messages.reload}</button><script>function reloadPage(){location.reload(!0)}</script></body></html>`;
|
||||
}
|
||||
|
||||
globalThis.addEventListener('fetch', ev => {
|
||||
let isHTMLRequest = false;
|
||||
if (ev.request.headers.get('sec-fetch-dest') === 'document') {
|
||||
@ -50,18 +99,7 @@ globalThis.addEventListener('fetch', ev => {
|
||||
}
|
||||
|
||||
if (!isHTMLRequest) return;
|
||||
ev.respondWith(
|
||||
fetch(ev.request)
|
||||
.catch(async () => {
|
||||
const html = await offlineContentHTML();
|
||||
return new Response(html, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'content-type': 'text/html',
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
ev.respondWith(respondToNavigation(ev.request));
|
||||
});
|
||||
|
||||
globalThis.addEventListener('push', ev => {
|
||||
|
||||
206
pnpm-lock.yaml
206
pnpm-lock.yaml
@ -22,12 +22,6 @@ importers:
|
||||
execa:
|
||||
specifier: 9.6.0
|
||||
version: 9.6.0
|
||||
fast-glob:
|
||||
specifier: 3.3.3
|
||||
version: 3.3.3
|
||||
glob:
|
||||
specifier: 13.0.0
|
||||
version: 13.0.0
|
||||
ignore-walk:
|
||||
specifier: 8.0.0
|
||||
version: 8.0.0
|
||||
@ -105,9 +99,6 @@ importers:
|
||||
'@fastify/accepts':
|
||||
specifier: 5.0.3
|
||||
version: 5.0.3
|
||||
'@fastify/cookie':
|
||||
specifier: 11.0.2
|
||||
version: 11.0.2
|
||||
'@fastify/cors':
|
||||
specifier: 11.1.0
|
||||
version: 11.1.0
|
||||
@ -201,9 +192,6 @@ importers:
|
||||
cacheable-lookup:
|
||||
specifier: 7.0.0
|
||||
version: 7.0.0
|
||||
cbor:
|
||||
specifier: 10.0.11
|
||||
version: 10.0.11
|
||||
chalk:
|
||||
specifier: 5.6.2
|
||||
version: 5.6.2
|
||||
@ -273,9 +261,6 @@ importers:
|
||||
jsonld:
|
||||
specifier: 9.0.0
|
||||
version: 9.0.0
|
||||
jsrsasign:
|
||||
specifier: 11.1.0
|
||||
version: 11.1.0
|
||||
juice:
|
||||
specifier: 11.0.3
|
||||
version: 11.0.3
|
||||
@ -315,9 +300,6 @@ importers:
|
||||
nsfwjs:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0(@tensorflow/tfjs@4.22.0(encoding@0.1.13)(seedrandom@3.0.5))(buffer@6.0.3)
|
||||
oauth:
|
||||
specifier: 0.10.2
|
||||
version: 0.10.2
|
||||
oauth2orize:
|
||||
specifier: 1.12.0
|
||||
version: 1.12.0
|
||||
@ -402,9 +384,6 @@ importers:
|
||||
tsc-alias:
|
||||
specifier: 1.8.16
|
||||
version: 1.8.16
|
||||
tsconfig-paths:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0
|
||||
typeorm:
|
||||
specifier: 0.3.27
|
||||
version: 0.3.27(ioredis@5.8.2)(pg@8.16.3)(reflect-metadata@0.2.2)
|
||||
@ -472,9 +451,6 @@ importers:
|
||||
'@types/jsonld':
|
||||
specifier: 1.5.15
|
||||
version: 1.5.15
|
||||
'@types/jsrsasign':
|
||||
specifier: 10.5.15
|
||||
version: 10.5.15
|
||||
'@types/mime-types':
|
||||
specifier: 3.0.1
|
||||
version: 3.0.1
|
||||
@ -487,9 +463,6 @@ importers:
|
||||
'@types/nodemailer':
|
||||
specifier: 7.0.4
|
||||
version: 7.0.4
|
||||
'@types/oauth':
|
||||
specifier: 0.9.6
|
||||
version: 0.9.6
|
||||
'@types/oauth2orize':
|
||||
specifier: 1.11.5
|
||||
version: 1.11.5
|
||||
@ -550,6 +523,9 @@ importers:
|
||||
aws-sdk-client-mock:
|
||||
specifier: 4.1.0
|
||||
version: 4.1.0
|
||||
cbor:
|
||||
specifier: 10.0.11
|
||||
version: 10.0.11
|
||||
cross-env:
|
||||
specifier: 10.1.0
|
||||
version: 10.1.0
|
||||
@ -568,9 +544,6 @@ importers:
|
||||
jest-mock:
|
||||
specifier: 29.7.0
|
||||
version: 29.7.0
|
||||
jest-util:
|
||||
specifier: 29.7.0
|
||||
version: 29.7.0
|
||||
js-yaml:
|
||||
specifier: 4.1.1
|
||||
version: 4.1.1
|
||||
@ -719,18 +692,12 @@ importers:
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: 6.0.2
|
||||
version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(sass@1.94.2)(terser@5.44.1)(tsx@4.20.6))(vue@3.5.25(typescript@5.9.3))
|
||||
'@vue/compiler-sfc':
|
||||
specifier: 3.5.25
|
||||
version: 3.5.25
|
||||
aiscript-vscode:
|
||||
specifier: github:aiscript-dev/aiscript-vscode#v0.1.15
|
||||
version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/c3cde89e79a41d93540cf8a48cd619c3f2dcb1b7
|
||||
analytics:
|
||||
specifier: 0.8.19
|
||||
version: 0.8.19(@types/dlv@1.1.5)
|
||||
astring:
|
||||
specifier: 1.9.0
|
||||
version: 1.9.0
|
||||
broadcast-channel:
|
||||
specifier: 7.2.0
|
||||
version: 7.2.0
|
||||
@ -767,9 +734,6 @@ importers:
|
||||
date-fns:
|
||||
specifier: 4.1.0
|
||||
version: 4.1.0
|
||||
estree-walker:
|
||||
specifier: 3.0.3
|
||||
version: 3.0.3
|
||||
eventemitter3:
|
||||
specifier: 5.0.1
|
||||
version: 5.0.1
|
||||
@ -803,9 +767,6 @@ importers:
|
||||
json5:
|
||||
specifier: 2.2.3
|
||||
version: 2.2.3
|
||||
magic-string:
|
||||
specifier: 0.30.21
|
||||
version: 0.30.21
|
||||
matter-js:
|
||||
specifier: 0.20.0
|
||||
version: 0.20.0
|
||||
@ -848,9 +809,6 @@ importers:
|
||||
shiki:
|
||||
specifier: 3.17.0
|
||||
version: 3.17.0
|
||||
strict-event-emitter-types:
|
||||
specifier: 2.0.0
|
||||
version: 2.0.0
|
||||
textarea-caret:
|
||||
specifier: 3.1.0
|
||||
version: 3.1.0
|
||||
@ -863,15 +821,6 @@ importers:
|
||||
tinycolor2:
|
||||
specifier: 1.6.0
|
||||
version: 1.6.0
|
||||
tsc-alias:
|
||||
specifier: 1.8.16
|
||||
version: 1.8.16
|
||||
tsconfig-paths:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0
|
||||
typescript:
|
||||
specifier: 5.9.3
|
||||
version: 5.9.3
|
||||
v-code-diff:
|
||||
specifier: 1.13.1
|
||||
version: 1.13.1(vue@3.5.25(typescript@5.9.3))
|
||||
@ -978,9 +927,6 @@ importers:
|
||||
'@types/tinycolor2':
|
||||
specifier: 1.4.6
|
||||
version: 1.4.6
|
||||
'@types/ws':
|
||||
specifier: 8.18.1
|
||||
version: 8.18.1
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: 8.48.0
|
||||
version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
|
||||
@ -993,12 +939,12 @@ importers:
|
||||
'@vue/compiler-core':
|
||||
specifier: 3.5.25
|
||||
version: 3.5.25
|
||||
'@vue/runtime-core':
|
||||
specifier: 3.5.25
|
||||
version: 3.5.25
|
||||
acorn:
|
||||
specifier: 8.15.0
|
||||
version: 8.15.0
|
||||
astring:
|
||||
specifier: 1.9.0
|
||||
version: 1.9.0
|
||||
cross-env:
|
||||
specifier: 10.1.0
|
||||
version: 10.1.0
|
||||
@ -1011,15 +957,18 @@ importers:
|
||||
eslint-plugin-vue:
|
||||
specifier: 10.6.2
|
||||
version: 10.6.2(@stylistic/eslint-plugin@5.5.0(eslint@9.39.1))(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
|
||||
fast-glob:
|
||||
specifier: 3.3.3
|
||||
version: 3.3.3
|
||||
estree-walker:
|
||||
specifier: 3.0.3
|
||||
version: 3.0.3
|
||||
happy-dom:
|
||||
specifier: 20.0.11
|
||||
version: 20.0.11
|
||||
intersection-observer:
|
||||
specifier: 0.12.2
|
||||
version: 0.12.2
|
||||
magic-string:
|
||||
specifier: 0.30.21
|
||||
version: 0.30.21
|
||||
micromatch:
|
||||
specifier: 4.0.8
|
||||
version: 4.0.8
|
||||
@ -1059,6 +1008,9 @@ importers:
|
||||
tsx:
|
||||
specifier: 4.20.6
|
||||
version: 4.20.6
|
||||
typescript:
|
||||
specifier: 5.9.3
|
||||
version: 5.9.3
|
||||
vite-plugin-glsl:
|
||||
specifier: 1.5.4
|
||||
version: 1.5.4(@rollup/pluginutils@5.3.0(rollup@4.53.3))(esbuild@0.27.0)(vite@7.2.4(@types/node@24.10.1)(sass@1.94.2)(terser@5.44.1)(tsx@4.20.6))
|
||||
@ -1135,12 +1087,6 @@ importers:
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: 6.0.2
|
||||
version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(sass@1.94.2)(terser@5.44.1)(tsx@4.20.6))(vue@3.5.25(typescript@5.9.3))
|
||||
'@vue/compiler-sfc':
|
||||
specifier: 3.5.25
|
||||
version: 3.5.25
|
||||
astring:
|
||||
specifier: 1.9.0
|
||||
version: 1.9.0
|
||||
buraha:
|
||||
specifier: 0.0.1
|
||||
version: 0.0.1
|
||||
@ -1180,15 +1126,6 @@ importers:
|
||||
tinycolor2:
|
||||
specifier: 1.6.0
|
||||
version: 1.6.0
|
||||
tsc-alias:
|
||||
specifier: 1.8.16
|
||||
version: 1.8.16
|
||||
tsconfig-paths:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0
|
||||
typescript:
|
||||
specifier: 5.9.3
|
||||
version: 5.9.3
|
||||
uuid:
|
||||
specifier: 13.0.0
|
||||
version: 13.0.0
|
||||
@ -1250,9 +1187,6 @@ importers:
|
||||
eslint-plugin-vue:
|
||||
specifier: 10.6.2
|
||||
version: 10.6.2(@stylistic/eslint-plugin@5.5.0(eslint@9.39.1))(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
|
||||
fast-glob:
|
||||
specifier: 3.3.3
|
||||
version: 3.3.3
|
||||
happy-dom:
|
||||
specifier: 20.0.11
|
||||
version: 20.0.11
|
||||
@ -1277,6 +1211,9 @@ importers:
|
||||
tsx:
|
||||
specifier: 4.20.6
|
||||
version: 4.20.6
|
||||
typescript:
|
||||
specifier: 5.9.3
|
||||
version: 5.9.3
|
||||
vite-plugin-turbosnap:
|
||||
specifier: 1.0.3
|
||||
version: 1.0.3
|
||||
@ -1354,9 +1291,6 @@ importers:
|
||||
execa:
|
||||
specifier: 9.6.0
|
||||
version: 9.6.0
|
||||
glob:
|
||||
specifier: 11.1.0
|
||||
version: 11.1.0
|
||||
nodemon:
|
||||
specifier: 3.1.11
|
||||
version: 3.1.11
|
||||
@ -1375,9 +1309,6 @@ importers:
|
||||
harfbuzzjs:
|
||||
specifier: 0.4.13
|
||||
version: 0.4.13
|
||||
tiny-glob:
|
||||
specifier: 0.2.9
|
||||
version: 0.2.9
|
||||
tsx:
|
||||
specifier: 4.20.6
|
||||
version: 4.20.6
|
||||
@ -1434,9 +1365,6 @@ importers:
|
||||
execa:
|
||||
specifier: 9.6.0
|
||||
version: 9.6.0
|
||||
glob:
|
||||
specifier: 11.1.0
|
||||
version: 11.1.0
|
||||
nodemon:
|
||||
specifier: 3.1.11
|
||||
version: 3.1.11
|
||||
@ -1477,9 +1405,6 @@ importers:
|
||||
execa:
|
||||
specifier: 9.6.0
|
||||
version: 9.6.0
|
||||
glob:
|
||||
specifier: 13.0.0
|
||||
version: 13.0.0
|
||||
ncp:
|
||||
specifier: 2.0.0
|
||||
version: 2.0.0
|
||||
@ -1553,9 +1478,6 @@ importers:
|
||||
execa:
|
||||
specifier: 9.6.0
|
||||
version: 9.6.0
|
||||
glob:
|
||||
specifier: 11.1.0
|
||||
version: 11.1.0
|
||||
nodemon:
|
||||
specifier: 3.1.11
|
||||
version: 3.1.11
|
||||
@ -2527,9 +2449,6 @@ packages:
|
||||
'@fastify/busboy@3.2.0':
|
||||
resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==}
|
||||
|
||||
'@fastify/cookie@11.0.2':
|
||||
resolution: {integrity: sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==}
|
||||
|
||||
'@fastify/cors@11.1.0':
|
||||
resolution: {integrity: sha512-sUw8ed8wP2SouWZTIbA7V2OQtMNpLj2W6qJOYhNdcmINTu6gsxVYXjQiM9mdi8UUDlcoDDJ/W2syPo1WB2QjYA==}
|
||||
|
||||
@ -4801,9 +4720,6 @@ packages:
|
||||
'@types/jsonld@1.5.15':
|
||||
resolution: {integrity: sha512-PlAFPZjL+AuGYmwlqwKEL0IMP8M8RexH0NIPGfCVWSQ041H2rR/8OlyZSD7KsCVoN8vCfWdtWDBxX8yBVP+xow==}
|
||||
|
||||
'@types/jsrsasign@10.5.15':
|
||||
resolution: {integrity: sha512-3stUTaSRtN09PPzVWR6aySD9gNnuymz+WviNHoTb85dKu+BjaV4uBbWWGykBBJkfwPtcNZVfTn2lbX00U+yhpQ==}
|
||||
|
||||
'@types/long@4.0.2':
|
||||
resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
|
||||
|
||||
@ -4858,9 +4774,6 @@ packages:
|
||||
'@types/oauth2orize@1.11.5':
|
||||
resolution: {integrity: sha512-C6hrRoh9hCnqis39OpeUZSwgw+TIzcV0CsxwJMGfQjTx4I1r+CLmuEPzoDJr5NRTfc7OMwHNLkQwrGFLKrJjMQ==}
|
||||
|
||||
'@types/oauth@0.9.6':
|
||||
resolution: {integrity: sha512-H9TRCVKBNOhZZmyHLqFt9drPM9l+ShWiqqJijU1B8P3DX3ub84NjxDuy+Hjrz+fEca5Kwip3qPMKNyiLgNJtIA==}
|
||||
|
||||
'@types/offscreencanvas@2019.3.0':
|
||||
resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
|
||||
|
||||
@ -5262,15 +5175,9 @@ packages:
|
||||
'@volar/typescript@2.4.23':
|
||||
resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==}
|
||||
|
||||
'@vue/compiler-core@3.5.24':
|
||||
resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==}
|
||||
|
||||
'@vue/compiler-core@3.5.25':
|
||||
resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==}
|
||||
|
||||
'@vue/compiler-dom@3.5.24':
|
||||
resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==}
|
||||
|
||||
'@vue/compiler-dom@3.5.25':
|
||||
resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==}
|
||||
|
||||
@ -5313,9 +5220,6 @@ packages:
|
||||
peerDependencies:
|
||||
vue: 3.5.25
|
||||
|
||||
'@vue/shared@3.5.24':
|
||||
resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==}
|
||||
|
||||
'@vue/shared@3.5.25':
|
||||
resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==}
|
||||
|
||||
@ -7283,10 +7187,6 @@ packages:
|
||||
engines: {node: 20 || >=22}
|
||||
hasBin: true
|
||||
|
||||
glob@13.0.0:
|
||||
resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
@ -7307,16 +7207,10 @@ packages:
|
||||
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
globalyzer@0.1.0:
|
||||
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
|
||||
|
||||
globby@11.1.0:
|
||||
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
globrex@0.1.2:
|
||||
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
|
||||
|
||||
google-protobuf@3.21.4:
|
||||
resolution: {integrity: sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==}
|
||||
|
||||
@ -8133,9 +8027,6 @@ packages:
|
||||
resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
|
||||
engines: {'0': node >=0.6.0}
|
||||
|
||||
jsrsasign@11.1.0:
|
||||
resolution: {integrity: sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==}
|
||||
|
||||
jstransformer@1.0.0:
|
||||
resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==}
|
||||
|
||||
@ -8873,9 +8764,6 @@ packages:
|
||||
resolution: {integrity: sha512-j4XtFDQUBsvUHPjUmvmNDUDMYed2MphMIJBhyxVVe8hGCjkuYnjIsW+D9qk8c5ciXRdnk6x6tEbiO6PLeOZdCQ==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
oauth@0.10.2:
|
||||
resolution: {integrity: sha512-JtFnB+8nxDEXgNyniwz573xxbKSOu3R8D40xQKqcjwJ2CDkYqUDI53o6IuzDJBx60Z8VKCm271+t8iFjakrl8Q==}
|
||||
|
||||
object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -10509,9 +10397,6 @@ packages:
|
||||
through@2.3.8:
|
||||
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
||||
|
||||
tiny-glob@0.2.9:
|
||||
resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}
|
||||
|
||||
tiny-invariant@1.3.3:
|
||||
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||
|
||||
@ -12905,11 +12790,6 @@ snapshots:
|
||||
|
||||
'@fastify/busboy@3.2.0': {}
|
||||
|
||||
'@fastify/cookie@11.0.2':
|
||||
dependencies:
|
||||
cookie: 1.0.2
|
||||
fastify-plugin: 5.1.0
|
||||
|
||||
'@fastify/cors@11.1.0':
|
||||
dependencies:
|
||||
fastify-plugin: 5.1.0
|
||||
@ -15582,8 +15462,6 @@ snapshots:
|
||||
|
||||
'@types/jsonld@1.5.15': {}
|
||||
|
||||
'@types/jsrsasign@10.5.15': {}
|
||||
|
||||
'@types/long@4.0.2': {}
|
||||
|
||||
'@types/matter-js@0.20.2': {}
|
||||
@ -15643,10 +15521,6 @@ snapshots:
|
||||
'@types/express': 5.0.4
|
||||
'@types/node': 24.10.1
|
||||
|
||||
'@types/oauth@0.9.6':
|
||||
dependencies:
|
||||
'@types/node': 24.10.1
|
||||
|
||||
'@types/offscreencanvas@2019.3.0': {}
|
||||
|
||||
'@types/offscreencanvas@2019.7.3': {}
|
||||
@ -16181,14 +16055,6 @@ snapshots:
|
||||
path-browserify: 1.0.1
|
||||
vscode-uri: 3.1.0
|
||||
|
||||
'@vue/compiler-core@3.5.24':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@vue/shared': 3.5.24
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-core@3.5.25':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
@ -16197,11 +16063,6 @@ snapshots:
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-dom@3.5.24':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.24
|
||||
'@vue/shared': 3.5.24
|
||||
|
||||
'@vue/compiler-dom@3.5.25':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.25
|
||||
@ -16232,9 +16093,9 @@ snapshots:
|
||||
'@vue/language-core@2.2.12(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@volar/language-core': 2.4.15
|
||||
'@vue/compiler-dom': 3.5.24
|
||||
'@vue/compiler-dom': 3.5.25
|
||||
'@vue/compiler-vue2': 2.7.16
|
||||
'@vue/shared': 3.5.24
|
||||
'@vue/shared': 3.5.25
|
||||
alien-signals: 1.0.13
|
||||
minimatch: 9.0.5
|
||||
muggle-string: 0.4.1
|
||||
@ -16245,8 +16106,8 @@ snapshots:
|
||||
'@vue/language-core@3.1.5(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@volar/language-core': 2.4.23
|
||||
'@vue/compiler-dom': 3.5.24
|
||||
'@vue/shared': 3.5.24
|
||||
'@vue/compiler-dom': 3.5.25
|
||||
'@vue/shared': 3.5.25
|
||||
alien-signals: 3.1.0
|
||||
muggle-string: 0.4.1
|
||||
path-browserify: 1.0.1
|
||||
@ -16276,8 +16137,6 @@ snapshots:
|
||||
'@vue/shared': 3.5.25
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
|
||||
'@vue/shared@3.5.24': {}
|
||||
|
||||
'@vue/shared@3.5.25': {}
|
||||
|
||||
'@vue/test-utils@2.4.6':
|
||||
@ -18789,12 +18648,6 @@ snapshots:
|
||||
package-json-from-dist: 1.0.1
|
||||
path-scurry: 2.0.1
|
||||
|
||||
glob@13.0.0:
|
||||
dependencies:
|
||||
minimatch: 10.1.1
|
||||
minipass: 7.1.2
|
||||
path-scurry: 2.0.1
|
||||
|
||||
glob@7.2.3:
|
||||
dependencies:
|
||||
fs.realpath: 1.0.0
|
||||
@ -18817,8 +18670,6 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
gopd: 1.2.0
|
||||
|
||||
globalyzer@0.1.0: {}
|
||||
|
||||
globby@11.1.0:
|
||||
dependencies:
|
||||
array-union: 2.1.0
|
||||
@ -18828,8 +18679,6 @@ snapshots:
|
||||
merge2: 1.4.1
|
||||
slash: 3.0.0
|
||||
|
||||
globrex@0.1.2: {}
|
||||
|
||||
google-protobuf@3.21.4:
|
||||
optional: true
|
||||
|
||||
@ -19860,8 +19709,6 @@ snapshots:
|
||||
json-schema: 0.4.0
|
||||
verror: 1.10.0
|
||||
|
||||
jsrsasign@11.1.0: {}
|
||||
|
||||
jstransformer@1.0.0:
|
||||
dependencies:
|
||||
is-promise: 2.2.2
|
||||
@ -20784,8 +20631,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
oauth@0.10.2: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
object-inspect@1.13.4: {}
|
||||
@ -22588,11 +22433,6 @@ snapshots:
|
||||
|
||||
through@2.3.8: {}
|
||||
|
||||
tiny-glob@0.2.9:
|
||||
dependencies:
|
||||
globalyzer: 0.1.0
|
||||
globrex: 0.1.2
|
||||
|
||||
tiny-invariant@1.3.3: {}
|
||||
|
||||
tinybench@2.9.0: {}
|
||||
@ -23168,7 +23008,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
'@vue/compiler-dom': 3.5.24
|
||||
'@vue/compiler-dom': 3.5.25
|
||||
'@vue/compiler-sfc': 3.5.25
|
||||
ast-types: 0.16.1
|
||||
esm-resolve: 1.0.11
|
||||
|
||||
@ -3,11 +3,10 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { createWriteStream } from 'node:fs';
|
||||
import { createWriteStream, promises as fsp } from 'node:fs';
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import glob from 'fast-glob';
|
||||
import walk from 'ignore-walk';
|
||||
import { Pack } from 'tar/pack';
|
||||
import meta from '../package.json' with { type: "json" };
|
||||
@ -25,7 +24,7 @@ export default async function build() {
|
||||
const pack = new Pack({ cwd, gzip: true });
|
||||
const patterns = await walk({ path: cwd, ignoreFiles: ['.gitignore'] });
|
||||
|
||||
for await (const entry of glob.stream(patterns, { cwd, ignore, dot: true })) {
|
||||
for await (const entry of fsp.glob(patterns, { cwd, ignore, dot: true })) {
|
||||
pack.add(entry);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user