Merge branch 'develop' into vue3

This commit is contained in:
syuilo 2020-08-09 10:32:21 +09:00
commit 2b89707012
32 changed files with 664 additions and 458 deletions

View File

@ -5,6 +5,7 @@
.vscode .vscode
Dockerfile Dockerfile
build/ build/
built/
db/ db/
docker-compose.yml docker-compose.yml
elasticsearch/ elasticsearch/

View File

@ -1,5 +1,43 @@
ChangeLog ChangeLog
========= =========
12.46.0 (2020/8/2)
------------------
### ✨Improvements
- チャットでCmd+Enterショートカットが使用できない問題を修正 [#6614](https://github.com/syuilo/misskey/pull/6614)
- サイドバーを折り畳めるように [#6610](https://github.com/syuilo/misskey/pull/6610)
### 🐛Fixes
- お知らせを既読にできない問題を修正 [9008664](https://github.com/syuilo/misskey/commit/9008664606483e2902f03929f0f696ac43de6db4)
- シンタックスハイライト構文が壊れている問題を修正 [60736ba](https://github.com/syuilo/misskey/commit/60736bab2ac974c2d2c2c106d297fa67fdaff87a)
12.45.1 (2020/8/1)
-------------------
### ✨Improvements
- 自分のノートにリアクションを押せるように [#6506](https://github.com/syuilo/misskey/pull/6506)
- 非ログイン時にウェルカムメッセージが被る問題を修正 [#6509](https://github.com/syuilo/misskey/pull/6509)
### 🐛Fixes
- 最新の投票結果がタイムラインなどに反映されない問題を修正 [2522e73](https://github.com/syuilo/misskey/commit/2522e7388d4d0b92d4517f2c07190e8f88394026)
12.45.0 (2020/7/30)
-------------------
### ✨Improvements
- プラグインのIDを不要に [57203de](https://github.com/syuilo/misskey/commit/57203de4cbf3947825f422dd746a076d79e353c7)
- プラグインの設定にdescriptionを表示できるように [9eee564](https://github.com/syuilo/misskey/commit/9eee5644b9b112ed6d8863edce569f4d554459f5)
- AiScript: Plugin:register_note_post_interruptor 関数を追加(ノート作成時の割り込み処理を登録できる) [e7de5f6](https://github.com/syuilo/misskey/commit/e7de5f60513774e9c599a2e3aac0fbeefb88236f)
- AiScript: Plugin:open_url 関数を追加 [60d81d7](https://github.com/syuilo/misskey/commit/60d81d74e35879f52a374d5e35fe25dc115d75a4)
### 🐛Fixes
- 通知のノートがリアクティブではない問題を修正 [2701a7e](https://github.com/syuilo/misskey/commit/2701a7e85fcf745e75b46b88b0fc9b3f76218e44)
- ピン留めされたノートがリアクティブではない問題を修正 [31a0afd](https://github.com/syuilo/misskey/commit/31a0afdaab309cd2e9fd22f0524730488202704d)
- プラグインの設定がnullになることがある問題を修正 [01e9b3c](https://github.com/syuilo/misskey/commit/01e9b3c2f634f37cee6820ca25d7576ef3ab6442)
12.44.1 (2020/7/29) 12.44.1 (2020/7/29)
------------------- -------------------
### 🐛Fixes ### 🐛Fixes

View File

@ -351,6 +351,9 @@ pluginInstallWarn: "يرجى تنصيب إضافات ذات مصدر موثوق
smtpHost: "المضيف" smtpHost: "المضيف"
smtpUser: "اسم المستخدم" smtpUser: "اسم المستخدم"
smtpPass: "الكلمة السرية" smtpPass: "الكلمة السرية"
_sidebar:
icon: "الصورة الرمزية"
hide: "إخفاء"
_theme: _theme:
explore: "استكشف قوالب المظهر" explore: "استكشف قوالب المظهر"
install: "تنصيب قالب" install: "تنصيب قالب"

View File

@ -556,6 +556,11 @@ testEmail: "Email-Versand testen"
wordMute: "Wort-Stummschaltung" wordMute: "Wort-Stummschaltung"
userSaysSomething: "{name} hat etwas gesagt." userSaysSomething: "{name} hat etwas gesagt."
makeActive: "Aktivieren" makeActive: "Aktivieren"
display: "Anzeige"
_sidebar:
full: "Voll"
icon: "Profilbild"
hide: "Ausblenden"
_wordMute: _wordMute:
muteWords: "Wort stummschalten" muteWords: "Wort stummschalten"
muteWordsDescription: "Mit Leerzeichen für eine \"UND\"-Verknüpfung trennen, durch Zeilenumbrüche für eine \"ODER\"-Verknüpfung trennen." muteWordsDescription: "Mit Leerzeichen für eine \"UND\"-Verknüpfung trennen, durch Zeilenumbrüche für eine \"ODER\"-Verknüpfung trennen."

View File

@ -556,6 +556,11 @@ testEmail: "Test email delivery"
wordMute: "Word mute" wordMute: "Word mute"
userSaysSomething: "{name} said something" userSaysSomething: "{name} said something"
makeActive: "Activate" makeActive: "Activate"
display: "Display"
_sidebar:
full: "Full"
icon: "Avatar"
hide: "Hide"
_wordMute: _wordMute:
muteWords: "Word to mute" muteWords: "Word to mute"
muteWordsDescription: "Separate with spaces for AND condition. Separate with line breaks for OR." muteWordsDescription: "Separate with spaces for AND condition. Separate with line breaks for OR."

View File

@ -104,6 +104,8 @@ unblockConfirm: "¿Quiere dejar de bloquear esta cuenta?"
suspendConfirm: "¿Quiere suspender esta cuenta?" suspendConfirm: "¿Quiere suspender esta cuenta?"
unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?" unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
selectList: "Seleccione una lista" selectList: "Seleccione una lista"
selectAntenna: "Seleccionar antena"
selectWidget: "Seleccionar widget"
customEmojis: "Emojis personalizados" customEmojis: "Emojis personalizados"
emoji: "Emoji" emoji: "Emoji"
emojiName: "Nombre del emoji" emojiName: "Nombre del emoji"
@ -535,6 +537,8 @@ enableAll: "Activar todo"
disableAll: "Desactivar todo" disableAll: "Desactivar todo"
tokenRequested: "Permiso de acceso a la cuenta" tokenRequested: "Permiso de acceso a la cuenta"
pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos aquí" pluginTokenRequestedDescription: "Este plugin podrá usar los permisos descritos aquí"
notificationType: "Tipo de notificación"
edit: "Editar"
useStarForReactionFallback: "En caso de que los emojis de reacciones no sean claros, usar en su lugar una estrella" useStarForReactionFallback: "En caso de que los emojis de reacciones no sean claros, usar en su lugar una estrella"
emailConfig: "Configuración del servidor de correos" emailConfig: "Configuración del servidor de correos"
enableEmail: "Activar el envío de correos electrónicos" enableEmail: "Activar el envío de correos electrónicos"
@ -549,6 +553,20 @@ emptyToDisableSmtpAuth: "Deje el nombre del usuario y la contraseña en blanco p
smtpSecure: "Usar SSL/TLS implícito en la conexión SMTP" smtpSecure: "Usar SSL/TLS implícito en la conexión SMTP"
smtpSecureInfo: "Apagar cuando se use STARTTLS" smtpSecureInfo: "Apagar cuando se use STARTTLS"
testEmail: "Prueba de envío" testEmail: "Prueba de envío"
wordMute: "Silenciar palabras"
userSaysSomething: "{name} dijo algo"
makeActive: "Activar"
_sidebar:
icon: "Avatar"
hide: "Ocultar"
_wordMute:
muteWords: "Palabras que silenciar"
muteWordsDescription: "Separar con espacios indica una declaracion And, separar con lineas nuevas indica una declaracion Or。"
muteWordsDescription2: "Encerrar las palabras clave entre numerales para usar expresiones regulares"
softDescription: "Ocultar en la linea de tiempo las notas que cumplen las condiciones"
hardDescription: "Evitar que se agreguen a la linea de tiempo las notas que cumplen las condiciones. Las notas no agregadas seguirán quitadas aunque cambien las condiciones."
soft: "Suave"
hard: "Duro"
_theme: _theme:
explore: "Explorar temas" explore: "Explorar temas"
install: "Instalar tema" install: "Instalar tema"
@ -1189,15 +1207,25 @@ _notification:
yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada" yourFollowRequestAccepted: "Tu solicitud de seguimiento fue aceptada"
youWereInvitedToGroup: "Invitado al grupo" youWereInvitedToGroup: "Invitado al grupo"
_types: _types:
all: "Todo"
follow: "Siguiendo" follow: "Siguiendo"
mention: "Menciones" mention: "Menciones"
reply: "Respuestas"
renote: "Renotar" renote: "Renotar"
quote: "Citar" quote: "Citar"
reaction: "Reacción" reaction: "Reacción"
pollVote: "Encuestas"
receiveFollowRequest: "Solicitudes de seguimiento"
_deck: _deck:
alwaysShowMainColumn: "Siempre mostrar la columna principal" alwaysShowMainColumn: "Siempre mostrar la columna principal"
columnAlign: "Alinear columnas" columnAlign: "Alinear columnas"
addColumn: "Agregar columna" addColumn: "Agregar columna"
swapLeft: "Mover a la izquierda"
swapRight: "Mover a la derecha"
swapUp: "Mover arriba"
swapDown: "Mover abajo"
stackLeft: "Apilar a la izquierda"
popRight: "Sacar a la derecha"
_columns: _columns:
widgets: "Widgets" widgets: "Widgets"
notifications: "Notificaciones" notifications: "Notificaciones"

View File

@ -543,6 +543,9 @@ emailConfig: "Configuration du serveur email"
smtpHost: "Hôte" smtpHost: "Hôte"
smtpUser: "Nom dutilisateur·rice" smtpUser: "Nom dutilisateur·rice"
smtpPass: "Mot de passe" smtpPass: "Mot de passe"
_sidebar:
icon: "Avatar"
hide: "Masquer"
_theme: _theme:
explore: "Explorer les thèmes" explore: "Explorer les thèmes"
install: "Installer un thème" install: "Installer un thème"

View File

@ -556,6 +556,13 @@ testEmail: "配信テスト"
wordMute: "ワードミュート" wordMute: "ワードミュート"
userSaysSomething: "{name}が何かを言いました" userSaysSomething: "{name}が何かを言いました"
makeActive: "アクティブにする" makeActive: "アクティブにする"
display: "表示"
copy: "コピー"
_sidebar:
full: "フル"
icon: "アイコン"
hide: "隠す"
_wordMute: _wordMute:
muteWords: "ミュートするワード" muteWords: "ミュートするワード"

View File

@ -356,6 +356,8 @@ invites: "来てや"
smtpHost: "ホスト" smtpHost: "ホスト"
smtpUser: "ユーザー名" smtpUser: "ユーザー名"
smtpPass: "パスワード" smtpPass: "パスワード"
_sidebar:
icon: "アイコン"
_theme: _theme:
keys: keys:
renote: "Renote" renote: "Renote"

View File

@ -104,6 +104,8 @@ unblockConfirm: "이 계정의 차단을 해제하시겠습니까?"
suspendConfirm: "이 계정을 정지하시겠습니까?" suspendConfirm: "이 계정을 정지하시겠습니까?"
unsuspendConfirm: "이 계정의 정지를 해제하시겠습니까?" unsuspendConfirm: "이 계정의 정지를 해제하시겠습니까?"
selectList: "리스트 선택" selectList: "리스트 선택"
selectAntenna: "안테나 선택"
selectWidget: "위젯 선택"
customEmojis: "커스텀 이모지" customEmojis: "커스텀 이모지"
emoji: "이모지" emoji: "이모지"
emojiName: "이모지 이름" emojiName: "이모지 이름"
@ -432,7 +434,7 @@ tags: "태그"
docSource: "이 문서의 소스" docSource: "이 문서의 소스"
createAccount: "계정 만들기" createAccount: "계정 만들기"
existingAcount: "기존 계정" existingAcount: "기존 계정"
regenerate: "다시 생성" regenerate: "생성"
fontSize: "글자 크기" fontSize: "글자 크기"
noFollowRequests: "처리되지 않은 팔로우 요청이 없습니다" noFollowRequests: "처리되지 않은 팔로우 요청이 없습니다"
openImageInNewTab: "새 탭에서 이미지 열기" openImageInNewTab: "새 탭에서 이미지 열기"
@ -527,9 +529,25 @@ plugins: "플러그인"
pluginInstallWarn: "신뢰할 수 없는 플러그인은 설치하지 마십시오." pluginInstallWarn: "신뢰할 수 없는 플러그인은 설치하지 마십시오."
deck: "덱" deck: "덱"
undeck: "덱 해제" undeck: "덱 해제"
generateAccessToken: "액세스 토큰 생성"
permission: "권한"
enableAll: "전체 선택"
disableAll: "전체 해제"
edit: "편집"
useStarForReactionFallback: "알 수 없는 리액션 이모지 대신 ★ 사용"
email: "메일 주소"
smtpConfig: "SMTP 서버 설정"
smtpHost: "호스트" smtpHost: "호스트"
smtpUser: "유저명" smtpUser: "유저명"
smtpPass: "비밀번호" smtpPass: "비밀번호"
emptyToDisableSmtpAuth: "SMTP 인증을 사용하지 않으려면 공란으로 비워둡니다."
smtpSecureInfo: "STARTTLS 사용 시에는 해제합니다."
wordMute: "단어 뮤트"
_sidebar:
icon: "아바타"
hide: "숨기기"
_wordMute:
muteWords: "뮤트할 단어"
_theme: _theme:
explore: "테마 찾아보기" explore: "테마 찾아보기"
install: "테마 설치" install: "테마 설치"
@ -1127,6 +1145,12 @@ _notification:
quote: "인용" quote: "인용"
reaction: "리액션" reaction: "리액션"
_deck: _deck:
swapLeft: "왼쪽으로 이동"
swapRight: "오른쪽으로 이동"
swapUp: "위로 이동"
swapDown: "아래로 이동"
stackLeft: "왼쪽에 쌓기"
popRight: "오른쪽으로 빼기"
_columns: _columns:
widgets: "위젯" widgets: "위젯"
notifications: "알림" notifications: "알림"

View File

@ -104,6 +104,7 @@ unblockConfirm: "确定要解除屏蔽吗?"
suspendConfirm: "要冻结吗?" suspendConfirm: "要冻结吗?"
unsuspendConfirm: "要解除冻结吗?" unsuspendConfirm: "要解除冻结吗?"
selectList: "选择列表" selectList: "选择列表"
selectAntenna: "天线选择"
selectWidget: "选择小工具" selectWidget: "选择小工具"
customEmojis: "自定义Emoji" customEmojis: "自定义Emoji"
emoji: "表情符号" emoji: "表情符号"
@ -552,6 +553,19 @@ emptyToDisableSmtpAuth: "用户名和密码留空可以禁用SMTP验证"
smtpSecure: "在 SMTP 连接中使用隐式 SSL / TLS" smtpSecure: "在 SMTP 连接中使用隐式 SSL / TLS"
smtpSecureInfo: "使用STARTTLS时关闭。" smtpSecureInfo: "使用STARTTLS时关闭。"
testEmail: "邮件发送测试" testEmail: "邮件发送测试"
wordMute: "文字屏蔽"
userSaysSomething: "{name}说了什么"
makeActive: "激活"
display: "显示"
_sidebar:
icon: "头像"
hide: "隐藏"
_wordMute:
muteWords: "禁用词"
muteWordsDescription: "使用空格分隔表示AND逻辑使用换行符分隔表示OR逻辑。"
muteWordsDescription2: "将关键字用斜线括起来表示正则表达式。"
softDescription: "隐藏时间轴中指定条件的帖文。"
hardDescription: "防止将具有指定条件的帖文添加到时间线。 即使您更改条件,未添加的帖文也会被排除在外。"
_theme: _theme:
explore: "寻找主题" explore: "寻找主题"
install: "安装主题" install: "安装主题"
@ -1192,15 +1206,25 @@ _notification:
yourFollowRequestAccepted: "您的关注请求已通过" yourFollowRequestAccepted: "您的关注请求已通过"
youWereInvitedToGroup: "您有新的群组邀请" youWereInvitedToGroup: "您有新的群组邀请"
_types: _types:
all: "全部"
follow: "关注中" follow: "关注中"
mention: "提及" mention: "提及"
reply: "回复"
renote: "转发" renote: "转发"
quote: "引用" quote: "引用"
reaction: "回应" reaction: "回应"
pollVote: "投票"
receiveFollowRequest: "关注请求"
_deck: _deck:
alwaysShowMainColumn: "总是显示主列" alwaysShowMainColumn: "总是显示主列"
columnAlign: "列对齐" columnAlign: "列对齐"
addColumn: "添加列" addColumn: "添加列"
swapLeft: "向左移动"
swapRight: "向右移动"
swapUp: "向上移动"
swapDown: "向下移动"
stackLeft: "向左折叠"
popRight: "向右弹出"
_columns: _columns:
widgets: "小工具" widgets: "小工具"
notifications: "通知" notifications: "通知"

View File

@ -409,6 +409,8 @@ deletedNote: "已删除的貼文"
smtpHost: "主機" smtpHost: "主機"
smtpUser: "使用名稱" smtpUser: "使用名稱"
smtpPass: "密碼" smtpPass: "密碼"
_sidebar:
icon: "頭像"
_theme: _theme:
func: "函数" func: "函数"
keys: keys:

View File

@ -1,7 +1,7 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>", "author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.45.0", "version": "12.46.0",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",
@ -36,21 +36,21 @@
"mocha/serialize-javascript": "^3.1.0" "mocha/serialize-javascript": "^3.1.0"
}, },
"dependencies": { "dependencies": {
"@babel/plugin-transform-runtime": "7.10.3", "@babel/plugin-transform-runtime": "7.11.0",
"@elastic/elasticsearch": "7.8.0", "@elastic/elasticsearch": "7.8.0",
"@fortawesome/fontawesome-svg-core": "1.2.29", "@fortawesome/fontawesome-svg-core": "1.2.30",
"@fortawesome/free-brands-svg-icons": "5.13.1", "@fortawesome/free-brands-svg-icons": "5.14.0",
"@fortawesome/free-regular-svg-icons": "5.13.1", "@fortawesome/free-regular-svg-icons": "5.14.0",
"@fortawesome/free-solid-svg-icons": "5.13.1", "@fortawesome/free-solid-svg-icons": "5.14.0",
"@fortawesome/vue-fontawesome": "0.1.10", "@fortawesome/vue-fontawesome": "0.1.10",
"@koa/cors": "3.1.0", "@koa/cors": "3.1.0",
"@koa/multer": "3.0.0", "@koa/multer": "3.0.0",
"@koa/router": "9.0.1", "@koa/router": "9.0.1",
"@sinonjs/fake-timers": "6.0.1", "@sinonjs/fake-timers": "6.0.1",
"@syuilo/aiscript": "0.10.0", "@syuilo/aiscript": "0.11.0",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/bull": "3.14.0", "@types/bull": "3.14.0",
"@types/cbor": "5.0.0", "@types/cbor": "5.0.1",
"@types/dateformat": "3.0.1", "@types/dateformat": "3.0.1",
"@types/double-ended-queue": "2.1.1", "@types/double-ended-queue": "2.1.1",
"@types/escape-regexp": "0.0.0", "@types/escape-regexp": "0.0.0",
@ -107,16 +107,16 @@
"@typescript-eslint/parser": "3.6.0", "@typescript-eslint/parser": "3.6.0",
"@vue/compiler-sfc": "3.0.0-rc.2", "@vue/compiler-sfc": "3.0.0-rc.2",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"apexcharts": "3.19.3", "apexcharts": "3.20.0",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autosize": "4.0.2", "autosize": "4.0.2",
"autwh": "0.1.0", "autwh": "0.1.0",
"aws-sdk": "2.713.0", "aws-sdk": "2.724.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.3", "blurhash": "1.1.3",
"bull": "3.15.0", "bull": "3.16.0",
"cafy": "15.2.1", "cafy": "15.2.1",
"cbor": "5.0.2", "cbor": "5.1.0",
"chalk": "4.1.0", "chalk": "4.1.0",
"chart.js": "2.9.3", "chart.js": "2.9.3",
"cli-highlight": "2.1.4", "cli-highlight": "2.1.4",
@ -124,7 +124,7 @@
"content-disposition": "0.5.3", "content-disposition": "0.5.3",
"core-js": "3.6.5", "core-js": "3.6.5",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "3.6.0", "css-loader": "4.2.1",
"cssnano": "4.1.10", "cssnano": "4.1.10",
"dateformat": "3.0.3", "dateformat": "3.0.3",
"deep-entries": "3.1.0", "deep-entries": "3.1.0",
@ -136,7 +136,7 @@
"eventemitter3": "4.0.4", "eventemitter3": "4.0.4",
"feed": "4.2.1", "feed": "4.2.1",
"fibers": "5.0.0", "fibers": "5.0.0",
"file-type": "14.6.2", "file-type": "14.7.1",
"fluent-ffmpeg": "2.1.2", "fluent-ffmpeg": "2.1.2",
"glob": "7.1.6", "glob": "7.1.6",
"gulp": "4.0.2", "gulp": "4.0.2",
@ -145,7 +145,7 @@
"gulp-rename": "2.0.0", "gulp-rename": "2.0.0",
"gulp-replace": "1.0.0", "gulp-replace": "1.0.0",
"gulp-sourcemaps": "2.6.5", "gulp-sourcemaps": "2.6.5",
"gulp-terser": "1.2.0", "gulp-terser": "1.3.2",
"gulp-tslint": "8.1.4", "gulp-tslint": "8.1.4",
"gulp-typescript": "6.0.0-alpha.1", "gulp-typescript": "6.0.0-alpha.1",
"hard-source-webpack-plugin": "0.13.1", "hard-source-webpack-plugin": "0.13.1",
@ -164,7 +164,7 @@
"json5-loader": "4.0.0", "json5-loader": "4.0.0",
"jsonld": "3.1.1", "jsonld": "3.1.1",
"jsrsasign": "8.0.20", "jsrsasign": "8.0.20",
"katex": "0.11.1", "katex": "0.12.0",
"koa": "2.13.0", "koa": "2.13.0",
"koa-bodyparser": "4.3.0", "koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0", "koa-favicon": "2.1.0",
@ -178,31 +178,30 @@
"lookup-dns-cache": "2.1.0", "lookup-dns-cache": "2.1.0",
"markdown-it": "11.0.0", "markdown-it": "11.0.0",
"markdown-it-anchor": "5.3.0", "markdown-it-anchor": "5.3.0",
"mocha": "8.0.1", "mocha": "8.1.1",
"moji": "0.5.1", "moji": "0.5.1",
"ms": "2.1.2", "ms": "2.1.2",
"multer": "1.4.2", "multer": "1.4.2",
"nested-property": "2.0.1", "nested-property": "2.0.1",
"node-fetch": "2.6.0", "node-fetch": "2.6.0",
"nodemailer": "6.4.10", "nodemailer": "6.4.11",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"object-assign-deep": "0.4.0", "object-assign-deep": "0.4.0",
"os-utils": "0.0.14", "os-utils": "0.0.14",
"parse5": "6.0.0", "parse5": "6.0.1",
"parsimmon": "1.14.0", "parsimmon": "1.15.0",
"pg": "8.3.0", "pg": "8.3.0",
"portscanner": "2.2.0", "portscanner": "2.2.0",
"postcss-loader": "3.0.0", "postcss-loader": "3.0.0",
"prismjs": "1.20.0", "prismjs": "1.21.0",
"probe-image-size": "5.0.0", "probe-image-size": "5.0.0",
"promise-limit": "2.7.0", "promise-limit": "2.7.0",
"promise-sequential": "1.1.1", "promise-sequential": "1.1.1",
"pug": "2.0.4", "pug": "2.0.4",
"punycode": "2.1.1", "punycode": "2.1.1",
"pureimage": "0.2.1", "pureimage": "0.2.4",
"qrcode": "1.4.4", "qrcode": "1.4.4",
"random-seed": "0.3.0", "random-seed": "0.3.0",
"randomcolor": "0.5.4",
"ratelimiter": "3.4.1", "ratelimiter": "3.4.1",
"re2": "1.15.4", "re2": "1.15.4",
"recaptcha-promise": "0.1.3", "recaptcha-promise": "0.1.3",
@ -210,7 +209,7 @@
"redis": "3.0.2", "redis": "3.0.2",
"redis-lock": "0.1.4", "redis-lock": "0.1.4",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"regenerator-runtime": "0.13.5", "regenerator-runtime": "0.13.7",
"rename": "1.0.4", "rename": "1.0.4",
"request-stats": "3.0.0", "request-stats": "3.0.0",
"require-all": "3.0.0", "require-all": "3.0.0",
@ -218,7 +217,7 @@
"rndstr": "1.0.0", "rndstr": "1.0.0",
"s-age": "1.1.2", "s-age": "1.1.2",
"sass": "1.26.10", "sass": "1.26.10",
"sass-loader": "9.0.2", "sass-loader": "9.0.3",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"sharp": "0.25.4", "sharp": "0.25.4",
"speakeasy": "2.0.0", "speakeasy": "2.0.0",
@ -226,35 +225,35 @@
"style-loader": "1.2.1", "style-loader": "1.2.1",
"summaly": "2.4.0", "summaly": "2.4.0",
"syslog-pro": "1.0.0", "syslog-pro": "1.0.0",
"systeminformation": "4.26.9", "systeminformation": "4.26.10",
"syuilo-password-strength": "0.0.1", "syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.117.1", "three": "0.117.1",
"tinycolor2": "1.4.1", "tinycolor2": "1.4.1",
"tmp": "0.2.1", "tmp": "0.2.1",
"ts-loader": "8.0.0", "ts-loader": "8.0.2",
"ts-node": "8.10.2", "ts-node": "8.10.2",
"tslint": "6.1.2", "tslint": "6.1.3",
"tslint-sonarts": "1.9.0", "tslint-sonarts": "1.9.0",
"typeorm": "0.2.25", "typeorm": "0.2.25",
"typescript": "3.9.6", "typescript": "3.9.7",
"ulid": "2.3.0", "ulid": "2.3.0",
"url-loader": "4.1.0", "url-loader": "4.1.0",
"uuid": "8.2.0", "uuid": "8.3.0",
"v-animate-css": "0.0.3", "v-animate-css": "0.0.3",
"v-debounce": "0.1.2", "v-debounce": "0.1.2",
"vue": "3.0.0-rc.5", "vue": "git+https://github.com/vuejs/vue-next.git#ed4381020fcea0494f19f11bebabd9108f2dafd7",
"vue-color": "2.7.1", "vue-color": "2.7.1",
"vue-content-loading": "1.6.0", "vue-content-loading": "1.6.0",
"vue-cropperjs": "4.1.0", "vue-cropperjs": "4.1.0",
"vue-i18n": "9.0.0-alpha.11", "vue-i18n": "9.0.0-alpha.11",
"vue-json-pretty": "1.6.5", "vue-json-pretty": "1.6.7",
"vue-loader": "16.0.0-beta.4", "vue-loader": "16.0.0-beta.4",
"vue-marquee-text-component": "1.1.1", "vue-marquee-text-component": "1.1.1",
"vue-meta": "2.4.0", "vue-meta": "2.4.0",
"vue-prism-component": "1.2.0", "vue-prism-component": "1.2.0",
"vue-prism-editor": "0.6.1", "vue-prism-editor": "0.6.1",
"vue-router": "4.0.0-beta.3", "vue-router": "4.0.0-beta.6",
"vue-style-loader": "4.1.2", "vue-style-loader": "4.1.2",
"vue-svg-inline-loader-corejs3": "1.5.0", "vue-svg-inline-loader-corejs3": "1.5.0",
"vue-template-compiler": "2.6.11", "vue-template-compiler": "2.6.11",
@ -262,7 +261,7 @@
"vuex": "4.0.0-beta.4", "vuex": "4.0.0-beta.4",
"vuex-persistedstate": "3.0.1", "vuex-persistedstate": "3.0.1",
"web-push": "3.4.4", "web-push": "3.4.4",
"webpack": "5.0.0-beta.22", "webpack": "git+https://github.com/webpack/webpack.git#c1237eae912817c7546e8c54489f7adb60bfbe38",
"webpack-cli": "3.3.12", "webpack-cli": "3.3.12",
"websocket": "1.0.31", "websocket": "1.0.31",
"ws": "7.3.1", "ws": "7.3.1",

View File

@ -18,6 +18,7 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { toUnicode } from 'punycode'; import { toUnicode } from 'punycode';
import { host as localHost } from '../config'; import { host as localHost } from '../config';
import { wellKnownServices } from '../../well-known-services';
export default defineComponent({ export default defineComponent({
props: { props: {
@ -37,12 +38,11 @@ export default defineComponent({
}, },
computed: { computed: {
url(): string { url(): string {
switch (this.host) { const wellKnown = wellKnownServices.find(x => x[0] === this.host);
case 'twitter.com': if (wellKnown) {
case 'github.com': return wellKnown[1](this.username);
return `https://${this.host}/${this.username}`; } else {
default: return `/${this.canonical}`;
return `/${this.canonical}`;
} }
}, },
canonical(): string { canonical(): string {

View File

@ -9,7 +9,7 @@
</transition> </transition>
<transition name="nav"> <transition name="nav">
<nav class="nav" v-show="showing"> <nav class="nav" :class="{ iconOnly, hidden }" v-show="showing">
<div> <div>
<button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn"> <button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn">
<mk-avatar :user="$store.state.i" class="avatar"/><mk-acct class="text" :user="$store.state.i"/> <mk-avatar :user="$store.state.i" class="avatar"/><mk-acct class="text" :user="$store.state.i"/>
@ -62,6 +62,8 @@ export default defineComponent({
menuDef: this.$store.getters.nav({ menuDef: this.$store.getters.nav({
search: this.search search: this.search
}), }),
iconOnly: false,
hidden: false,
faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
}; };
}, },
@ -85,9 +87,35 @@ export default defineComponent({
$route(to, from) { $route(to, from) {
this.showing = false; this.showing = false;
}, },
'$store.state.device.sidebarDisplay'() {
this.calcViewState();
},
iconOnly() {
this.$nextTick(() => {
this.$emit('change-view-mode');
});
},
hidden() {
this.$nextTick(() => {
this.$emit('change-view-mode');
});
}
},
created() {
window.addEventListener('resize', this.calcViewState);
this.calcViewState();
}, },
methods: { methods: {
calcViewState() {
this.iconOnly = (window.innerWidth <= 1279) || (this.$store.state.device.sidebarDisplay === 'icon');
this.hidden = (window.innerWidth <= 650) || (this.$store.state.device.sidebarDisplay === 'hide');
},
show() { show() {
this.showing = true; this.showing = true;
}, },
@ -314,10 +342,8 @@ export default defineComponent({
.mvcprjjd { .mvcprjjd {
$ui-font-size: 1em; // TODO: $ui-font-size: 1em; // TODO:
$nav-width: 250px; // TODO: $nav-width: 250px;
$nav-icon-only-width: 80px; // TODO: $nav-icon-only-width: 80px;
$nav-icon-only-threshold: 1279px; // TODO:
$nav-hide-threshold: 650px; // TODO:
> .nav-back { > .nav-back {
z-index: 1001; z-index: 1001;
@ -331,19 +357,66 @@ export default defineComponent({
width: $nav-width; width: $nav-width;
box-sizing: border-box; box-sizing: border-box;
@media (max-width: $nav-icon-only-threshold) { &.iconOnly {
flex: 0 0 $nav-icon-only-width; flex: 0 0 $nav-icon-only-width;
width: $nav-icon-only-width; width: $nav-icon-only-width;
&:not(.hidden) {
> div {
width: $nav-icon-only-width;
> .divider {
margin: 8px auto;
width: calc(100% - 32px);
}
> .item {
padding-left: 0;
width: 100%;
text-align: center;
font-size: $ui-font-size * 1.1;
line-height: 3.7rem;
> [data-icon],
> .avatar {
margin-right: 0;
}
> i {
left: 10px;
}
> .text {
display: none;
}
&:first-child {
margin-bottom: 8px;
}
&:last-child {
margin-top: 8px;
}
}
}
}
} }
@media (max-width: $nav-hide-threshold) { &.hidden {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
z-index: 1001; z-index: 1001;
> div {
> .index,
> .notifications {
display: none;
}
}
} }
@media (min-width: $nav-hide-threshold + 1px) { &:not(.hidden) {
display: block !important; display: block !important;
} }
@ -365,25 +438,6 @@ export default defineComponent({
border-top: solid 1px var(--divider); border-top: solid 1px var(--divider);
} }
@media (max-width: $nav-icon-only-threshold) and (min-width: $nav-hide-threshold + 1px) {
width: $nav-icon-only-width;
> .divider {
margin: 8px auto;
width: calc(100% - 32px);
}
> .item {
&:first-child {
margin-bottom: 8px;
}
&:last-child {
margin-top: 8px;
}
}
}
> .item { > .item {
position: relative; position: relative;
display: block; display: block;
@ -452,34 +506,6 @@ export default defineComponent({
margin-top: 16px; margin-top: 16px;
border-top: solid 1px var(--divider); border-top: solid 1px var(--divider);
} }
@media (max-width: $nav-icon-only-threshold) and (min-width: $nav-hide-threshold + 1px) {
padding-left: 0;
width: 100%;
text-align: center;
font-size: $ui-font-size * 1.2;
line-height: 3.7rem;
> [data-icon],
> .avatar {
margin-right: 0;
}
> i {
left: 10px;
}
> .text {
display: none;
}
}
}
@media (max-width: $nav-hide-threshold) {
> .index,
> .notifications {
display: none;
}
} }
} }
} }

View File

@ -2,8 +2,8 @@
<x-window ref="window" :width="400" :height="450" :no-padding="true" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="false" @ok="ok()" :can-close="false"> <x-window ref="window" :width="400" :height="450" :no-padding="true" @closed="() => { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="false" @ok="ok()" :can-close="false">
<template #header>{{ title || $t('generateAccessToken') }}</template> <template #header>{{ title || $t('generateAccessToken') }}</template>
<div class="ugkkpisj"> <div class="ugkkpisj">
<div> <div v-if="information">
<mk-info warn v-if="information">{{ information }}</mk-info> <mk-info warn>{{ information }}</mk-info>
</div> </div>
<div> <div>
<mk-input v-model="name">{{ $t('name') }}</mk-input> <mk-input v-model="name">{{ $t('name') }}</mk-input>

View File

@ -19,14 +19,14 @@ import MkButton from './button.vue';
import paging from '../../scripts/paging'; import paging from '../../scripts/paging';
export default defineComponent({ export default defineComponent({
mixins: [
paging({}),
],
components: { components: {
MkButton MkButton
}, },
mixins: [
paging({}),
],
props: { props: {
pagination: { pagination: {
required: true required: true

View File

@ -42,6 +42,7 @@ export default defineComponent({
}, },
methods: { methods: {
toggle() { toggle() {
if (this.disabled) return;
this.$emit('change', this.value); this.$emit('change', this.value);
} }
} }
@ -61,7 +62,10 @@ export default defineComponent({
&.disabled { &.disabled {
opacity: 0.6; opacity: 0.6;
cursor: not-allowed;
&, * {
cursor: not-allowed !important;
}
} }
&.checked { &.checked {

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="mk-app" v-hotkey.global="keymap"> <div class="mk-app" v-hotkey.global="keymap">
<header class="header"> <header class="header" ref="header">
<div class="title" ref="title"> <div class="title" ref="title">
<transition :name="$store.state.device.animation ? 'header' : ''" mode="out-in" appear> <transition :name="$store.state.device.animation ? 'header' : ''" mode="out-in" appear>
<button class="_button back" v-if="canBack" @click="back()"><fa :icon="faChevronLeft"/></button> <button class="_button back" v-if="canBack" @click="back()"><fa :icon="faChevronLeft"/></button>
@ -31,7 +31,7 @@
</div> </div>
</header> </header>
<x-sidebar ref="nav"/> <x-sidebar ref="nav" @change-view-mode="calcHeaderWidth"/>
<div class="contents" ref="contents" :class="{ wallpaper }"> <div class="contents" ref="contents" :class="{ wallpaper }">
<main ref="main"> <main ref="main">
@ -79,7 +79,7 @@
</template> </template>
</div> </div>
<div class="buttons"> <div class="buttons" :class="{ navHidden }">
<button class="button nav _button" @click="showNav" ref="navButton"><fa :icon="faBars"/><i v-if="navIndicated"><fa :icon="faCircle"/></i></button> <button class="button nav _button" @click="showNav" ref="navButton"><fa :icon="faBars"/><i v-if="navIndicated"><fa :icon="faCircle"/></i></button>
<button v-if="$route.name === 'index'" class="button home _button" @click="top()"><fa :icon="faHome"/></button> <button v-if="$route.name === 'index'" class="button home _button" @click="top()"><fa :icon="faHome"/></button>
<button v-else class="button home _button" @click="$router.push('/')"><fa :icon="faHome"/></button> <button v-else class="button home _button" @click="$router.push('/')"><fa :icon="faHome"/></button>
@ -87,7 +87,7 @@
<button v-if="$store.getters.isSignedIn" class="button post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button> <button v-if="$store.getters.isSignedIn" class="button post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>
</div> </div>
<button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button> <button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" :class="{ navHidden }" @click="post()"><fa :icon="faPencilAlt"/></button>
<stream-indicator v-if="$store.getters.isSignedIn"/> <stream-indicator v-if="$store.getters.isSignedIn"/>
</div> </div>
@ -126,6 +126,7 @@ export default defineComponent({
isDesktop: window.innerWidth >= DESKTOP_THRESHOLD, isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
canBack: false, canBack: false,
menuDef: this.$store.getters.nav({}), menuDef: this.$store.getters.nav({}),
navHidden: false,
wallpaper: localStorage.getItem('wallpaper') != null, wallpaper: localStorage.getItem('wallpaper') != null,
faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
}; };
@ -227,22 +228,15 @@ export default defineComponent({
}, },
mounted() { mounted() {
const adjustTitlePosition = () => { this.adjustTitlePosition();
const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.$el.offsetWidth;
if (left >= 0) {
this.$refs.title.style.left = left + 'px';
}
};
adjustTitlePosition();
const ro = new ResizeObserver((entries, observer) => { const ro = new ResizeObserver((entries, observer) => {
adjustTitlePosition(); this.adjustTitlePosition();
}); });
ro.observe(this.$refs.contents); ro.observe(this.$refs.contents);
window.addEventListener('resize', adjustTitlePosition, { passive: true }); window.addEventListener('resize', this.adjustTitlePosition, { passive: true });
if (!this.isDesktop) { if (!this.isDesktop) {
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
@ -252,9 +246,27 @@ export default defineComponent({
// widget follow // widget follow
this.attachSticky(); this.attachSticky();
this.$nextTick(() => {
this.calcHeaderWidth();
});
}, },
methods: { methods: {
adjustTitlePosition() {
const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.$el.offsetWidth;
if (left >= 0) {
this.$refs.title.style.left = left + 'px';
}
},
calcHeaderWidth() {
const navWidth = this.$refs.nav.$el.offsetWidth;
this.navHidden = navWidth === 0;
this.$refs.header.style.width = `calc(100% - ${navWidth}px)`;
this.adjustTitlePosition();
},
showNav() { showNav() {
this.$refs.nav.show(); this.$refs.nav.show();
}, },
@ -375,12 +387,8 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.mk-app { .mk-app {
$header-height: 60px; $header-height: 60px;
$nav-width: 250px; // TODO:
$nav-icon-only-width: 80px; // TODO:
$main-width: 670px; $main-width: 670px;
$ui-font-size: 1em; // TODO: $ui-font-size: 1em; // TODO:
$nav-icon-only-threshold: 1279px; // TODO:
$nav-hide-threshold: 650px; // TODO:
$header-sub-hide-threshold: 1090px; $header-sub-hide-threshold: 1090px;
$left-widgets-hide-threshold: 1600px; $left-widgets-hide-threshold: 1600px;
$right-widgets-hide-threshold: 1090px; $right-widgets-hide-threshold: 1090px;
@ -401,21 +409,13 @@ export default defineComponent({
top: 0; top: 0;
right: 0; right: 0;
height: $header-height; height: $header-height;
width: calc(100% - #{$nav-width}); width: 100%;
//background-color: var(--panel); //background-color: var(--panel);
-webkit-backdrop-filter: blur(32px); -webkit-backdrop-filter: blur(32px);
backdrop-filter: blur(32px); backdrop-filter: blur(32px);
background-color: var(--header); background-color: var(--header);
border-bottom: solid 1px var(--divider); border-bottom: solid 1px var(--divider);
@media (max-width: $nav-icon-only-threshold) {
width: calc(100% - #{$nav-icon-only-width});
}
@media (max-width: $nav-hide-threshold) {
width: 100%;
}
> .title { > .title {
position: relative; position: relative;
line-height: $header-height; line-height: $header-height;
@ -685,7 +685,7 @@ export default defineComponent({
} }
> .post { > .post {
display: none; display: block;
position: fixed; position: fixed;
z-index: 1000; z-index: 1000;
bottom: 32px; bottom: 32px;
@ -696,8 +696,8 @@ export default defineComponent({
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12); box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
font-size: 22px; font-size: 22px;
@media (min-width: ($nav-hide-threshold + 1px)) { &.navHidden {
display: block; display: none;
} }
@media (min-width: ($header-sub-hide-threshold + 1px)) { @media (min-width: ($header-sub-hide-threshold + 1px)) {
@ -719,7 +719,7 @@ export default defineComponent({
padding: 0 16px 16px 16px; padding: 0 16px 16px 16px;
} }
@media (min-width: ($nav-hide-threshold + 1px)) { &:not(.navHidden) {
display: none; display: none;
} }

View File

@ -11,7 +11,7 @@
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> <img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
</div> </div>
<div class="_footer" v-if="$store.getters.isSignedIn && !announcement.isRead"> <div class="_footer" v-if="$store.getters.isSignedIn && !announcement.isRead">
<mk-button @click="read(announcement)" primary><fa :icon="faCheck"/> {{ $t('gotIt') }}</mk-button> <mk-button @click="read(items, announcement, i)" primary><fa :icon="faCheck"/> {{ $t('gotIt') }}</mk-button>
</div> </div>
</section> </section>
</mk-pagination> </mk-pagination>
@ -47,8 +47,12 @@ export default defineComponent({
}, },
methods: { methods: {
read(announcement) { // TODO:
announcement.isRead = true; read(items, announcement, i) {
Vue.set(items, i, {
...announcement,
isRead: true,
});
this.$root.api('i/read-announcement', { announcementId: announcement.id }); this.$root.api('i/read-announcement', { announcementId: announcement.id });
}, },
} }

View File

@ -151,7 +151,7 @@ export default defineComponent({
}, },
onKeypress(e) { onKeypress(e) {
if ((e.which == 10 || e.which == 13) && e.ctrlKey && this.canSend) { if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey) && this.canSend) {
this.send(); this.send();
} }
}, },

View File

@ -55,16 +55,16 @@ export default defineComponent({
}, },
computed: { computed: {
isMe(): boolean { isMe(): boolean {
return this.message.userId == this.$store.state.i.id; return this.message.userId === this.$store.state.i.id;
}, },
urls(): string[] { urls(): string[] {
if (this.message.text) { if (this.message.text) {
const ast = parse(this.message.text); const ast = parse(this.message.text);
return unique(ast return unique(ast
.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent)) .filter(t => ((t.node.type === 'url' || t.node.type === 'link') && t.node.props.url && !t.node.props.silent))
.map(t => t.node.props.url)); .map(t => t.node.props.url));
} else { } else {
return null; return [];
} }
} }
}, },

View File

@ -221,14 +221,20 @@ export default defineComponent({
for (const id of x) { for (const id of x) {
if (this.messages.some(x => x.id == id)) { if (this.messages.some(x => x.id == id)) {
const exist = this.messages.map(x => x.id).indexOf(id); const exist = this.messages.map(x => x.id).indexOf(id);
this.messages[exist].isRead = true; this.messages[exist] = {
...this.messages[exist],
isRead: true,
};
} }
} }
} else if (this.group) { } else if (this.group) {
for (const id of x.ids) { for (const id of x.ids) {
if (this.messages.some(x => x.id == id)) { if (this.messages.some(x => x.id == id)) {
const exist = this.messages.map(x => x.id).indexOf(id); const exist = this.messages.map(x => x.id).indexOf(id);
this.messages[exist].reads.push(x.userId); this.messages[exist] = {
...this.messages[exist],
reads: [...this.messages[exist].reads, x.userId]
};
} }
} }
} }

View File

@ -7,6 +7,12 @@
<template #desc><button class="_textButton" @click="addItem">{{ $t('addItem') }}</button></template> <template #desc><button class="_textButton" @click="addItem">{{ $t('addItem') }}</button></template>
</mk-textarea> </mk-textarea>
</div> </div>
<div class="_content">
<div>{{ $t('display') }}</div>
<mk-radio v-model="sidebarDisplay" value="full">{{ $t('_sidebar.full') }}</mk-radio>
<mk-radio v-model="sidebarDisplay" value="icon">{{ $t('_sidebar.icon') }}</mk-radio>
<!-- <mk-radio v-model="sidebarDisplay" value="hide" disabled>{{ $t('_sidebar.hide') }}</mk-radio>--> <!-- TODO: UI -->
</div>
<div class="_footer"> <div class="_footer">
<mk-button inline @click="save()" primary><fa :icon="faSave"/> {{ $t('save') }}</mk-button> <mk-button inline @click="save()" primary><fa :icon="faSave"/> {{ $t('save') }}</mk-button>
<mk-button inline @click="reset()"><fa :icon="faRedo"/> {{ $t('default') }}</mk-button> <mk-button inline @click="reset()"><fa :icon="faRedo"/> {{ $t('default') }}</mk-button>
@ -19,12 +25,14 @@ import { defineComponent } from 'vue';
import { faListUl, faSave, faRedo } from '@fortawesome/free-solid-svg-icons'; import { faListUl, faSave, faRedo } from '@fortawesome/free-solid-svg-icons';
import MkButton from '../../components/ui/button.vue'; import MkButton from '../../components/ui/button.vue';
import MkTextarea from '../../components/ui/textarea.vue'; import MkTextarea from '../../components/ui/textarea.vue';
import MkRadio from '../../components/ui/radio.vue';
import { defaultDeviceUserSettings } from '../../store'; import { defaultDeviceUserSettings } from '../../store';
export default defineComponent({ export default defineComponent({
components: { components: {
MkButton, MkButton,
MkTextarea, MkTextarea,
MkRadio,
}, },
data() { data() {
@ -38,7 +46,12 @@ export default defineComponent({
computed: { computed: {
splited(): string[] { splited(): string[] {
return this.items.trim().split('\n').filter(x => x.trim() !== ''); return this.items.trim().split('\n').filter(x => x.trim() !== '');
} },
sidebarDisplay: {
get() { return this.$store.state.device.sidebarDisplay; },
set(value) { this.$store.commit('device/set', { key: 'sidebarDisplay', value }); }
},
}, },
created() { created() {

View File

@ -55,8 +55,8 @@
<mk-textarea v-model="installThemeCode"> <mk-textarea v-model="installThemeCode">
<span>{{ $t('_theme.code') }}</span> <span>{{ $t('_theme.code') }}</span>
</mk-textarea> </mk-textarea>
<mk-button @click="() => install(this.installThemeCode)" :disabled="installThemeCode == null" primary inline><fa :icon="faCheck"/> {{ $t('install') }}</mk-button> <mk-button @click="() => install(installThemeCode)" :disabled="installThemeCode == null" primary inline><fa :icon="faCheck"/> {{ $t('install') }}</mk-button>
<mk-button @click="() => preview(this.installThemeCode)" :disabled="installThemeCode == null" inline><fa :icon="faEye"/> {{ $t('preview') }}</mk-button> <mk-button @click="() => preview(installThemeCode)" :disabled="installThemeCode == null" inline><fa :icon="faEye"/> {{ $t('preview') }}</mk-button>
</details> </details>
</div> </div>
<div class="_content"> <div class="_content">
@ -68,6 +68,7 @@
<template v-if="selectedTheme"> <template v-if="selectedTheme">
<mk-textarea readonly tall :value="selectedThemeCode"> <mk-textarea readonly tall :value="selectedThemeCode">
<span>{{ $t('_theme.code') }}</span> <span>{{ $t('_theme.code') }}</span>
<template #desc><button @click="copyThemeCode()" class="_textButton">{{ $t('copy') }}</button></template>
</mk-textarea> </mk-textarea>
<mk-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="faTrashAlt"/> {{ $t('uninstall') }}</mk-button> <mk-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="faTrashAlt"/> {{ $t('uninstall') }}</mk-button>
</template> </template>
@ -80,7 +81,6 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye } from '@fortawesome/free-solid-svg-icons'; import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye } from '@fortawesome/free-solid-svg-icons';
import * as JSON5 from 'json5'; import * as JSON5 from 'json5';
import MkInput from '../../components/ui/input.vue';
import MkButton from '../../components/ui/button.vue'; import MkButton from '../../components/ui/button.vue';
import MkSelect from '../../components/ui/select.vue'; import MkSelect from '../../components/ui/select.vue';
import MkSwitch from '../../components/ui/switch.vue'; import MkSwitch from '../../components/ui/switch.vue';
@ -88,10 +88,10 @@ import MkTextarea from '../../components/ui/textarea.vue';
import { Theme, builtinThemes, applyTheme, validateTheme } from '../../scripts/theme'; import { Theme, builtinThemes, applyTheme, validateTheme } from '../../scripts/theme';
import { selectFile } from '../../scripts/select-file'; import { selectFile } from '../../scripts/select-file';
import { isDeviceDarkmode } from '../../scripts/is-device-darkmode'; import { isDeviceDarkmode } from '../../scripts/is-device-darkmode';
import copyToClipboard from '../../scripts/copy-to-clipboard';
export default defineComponent({ export default defineComponent({
components: { components: {
MkInput,
MkButton, MkButton,
MkSelect, MkSelect,
MkSwitch, MkSwitch,
@ -192,6 +192,14 @@ export default defineComponent({
}); });
}, },
copyThemeCode() {
copyToClipboard(this.selectedThemeCode);
this.$root.dialog({
type: 'success',
iconOnly: true, autoClose: true
});
},
parseThemeCode(code) { parseThemeCode(code) {
let theme; let theme;
@ -247,7 +255,7 @@ export default defineComponent({
key: 'themes', value: themes key: 'themes', value: themes
}); });
this.$root.dialog({ this.$root.dialog({
type: 'info', type: 'success',
iconOnly: true, autoClose: true iconOnly: true, autoClose: true
}); });
}, },

View File

@ -77,6 +77,7 @@ export const defaultDeviceSettings = {
enableInfiniteScroll: true, enableInfiniteScroll: true,
fixedWidgetsPosition: false, fixedWidgetsPosition: false,
useBlurEffectForModal: true, useBlurEffectForModal: true,
sidebarDisplay: 'full', // full, icon, hide
roomGraphicsQuality: 'medium', roomGraphicsQuality: 'medium',
roomUseOrthographicCamera: true, roomUseOrthographicCamera: true,
deckColumnAlign: 'left', deckColumnAlign: 'left',

View File

@ -3,6 +3,7 @@ import config from '../config';
import { intersperse } from '../prelude/array'; import { intersperse } from '../prelude/array';
import { MfmForest, MfmTree } from './prelude'; import { MfmForest, MfmTree } from './prelude';
import { IMentionedRemoteUsers } from '../models/entities/note'; import { IMentionedRemoteUsers } from '../models/entities/note';
import { wellKnownServices } from '../well-known-services';
export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) { export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
if (tokens == null) { if (tokens == null) {
@ -126,18 +127,13 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione
mention(token) { mention(token) {
const a = doc.createElement('a'); const a = doc.createElement('a');
const { username, host, acct } = token.node.props; const { username, host, acct } = token.node.props;
switch (host) { const wellKnown = wellKnownServices.find(x => x[0] === host);
case 'github.com': if (wellKnown) {
a.href = `https://github.com/${username}`; a.href = wellKnown[1](username);
break; } else {
case 'twitter.com': const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
a.href = `https://twitter.com/${username}`; a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${config.url}/${acct}`;
break; a.className = 'u-url mention';
default:
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${config.url}/${acct}`;
a.className = 'u-url mention';
break;
} }
a.textContent = acct; a.textContent = acct;
return a; return a;

View File

@ -56,11 +56,13 @@ export default define(meta, async (ps, user) => {
sha256.update(accessToken + app.secret); sha256.update(accessToken + app.secret);
const hash = sha256.digest('hex'); const hash = sha256.digest('hex');
const now = new Date();
// Insert access token doc // Insert access token doc
await AccessTokens.save({ await AccessTokens.save({
id: genId(), id: genId(),
createdAt: new Date(), createdAt: now,
lastUsedAt: new Date(), lastUsedAt: now,
appId: session.appId, appId: session.appId,
userId: user.id, userId: user.id,
token: accessToken, token: accessToken,

View File

@ -38,11 +38,13 @@ export default define(meta, async (ps, user) => {
// Generate access token // Generate access token
const accessToken = secureRndstr(32, true); const accessToken = secureRndstr(32, true);
const now = new Date();
// Insert access token doc // Insert access token doc
await AccessTokens.save({ await AccessTokens.save({
id: genId(), id: genId(),
createdAt: new Date(), createdAt: now,
lastUsedAt: new Date(), lastUsedAt: now,
session: ps.session, session: ps.session,
userId: user.id, userId: user.id,
token: accessToken, token: accessToken,

View File

@ -0,0 +1,4 @@
export const wellKnownServices = [
['twitter.com', username => `https://twitter.com/${username}`],
['github.com', username => `https://github.com/${username}`],
] as [string, (username: string) => string][];

View File

@ -61,7 +61,9 @@ module.exports = {
}, { }, {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
modules: true modules: true,
esModule: false, // TODO: trueにすると壊れる。Vue3移行の折にはtrueにできるかもしれない
url: false,
} }
}, postcss, { }, postcss, {
loader: 'sass-loader', loader: 'sass-loader',
@ -76,7 +78,11 @@ module.exports = {
use: [{ use: [{
loader: 'vue-style-loader' loader: 'vue-style-loader'
}, { }, {
loader: 'css-loader' loader: 'css-loader',
options: {
url: false,
esModule: false, // TODO: trueにすると壊れる。Vue3移行の折にはtrueにできるかもしれない
}
}, postcss, { }, postcss, {
loader: 'sass-loader', loader: 'sass-loader',
options: { options: {
@ -92,7 +98,10 @@ module.exports = {
use: [{ use: [{
loader: 'vue-style-loader' loader: 'vue-style-loader'
}, { }, {
loader: 'css-loader' loader: 'css-loader',
options: {
esModule: false, // TODO: trueにすると壊れる。Vue3移行の折にはtrueにできるかもしれない
}
}, postcss] }, postcss]
}, { }, {
test: /\.(eot|woff|woff2|svg|ttf)([?]?.*)$/, test: /\.(eot|woff|woff2|svg|ttf)([?]?.*)$/,

570
yarn.lock

File diff suppressed because it is too large Load Diff