Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcbe83cb38 | ||
|
|
37f983aee3 | ||
|
|
77de3f2b9d | ||
|
|
f655b54937 | ||
|
|
cac99ebdd4 | ||
|
|
f0d0a1546a | ||
|
|
8e8459fa55 | ||
|
|
d53c55ecb5 | ||
|
|
ea33d61a90 | ||
|
|
2fcc3388dd | ||
|
|
ef7f033c32 | ||
|
|
7aa54dc92e | ||
|
|
d10ad1b413 | ||
|
|
34063a0b84 | ||
|
|
8c9d975d69 | ||
|
|
03b072b894 | ||
|
|
d1bed49808 | ||
|
|
6c3417d9b5 | ||
|
|
ba65226460 | ||
|
|
9c9cd168ee | ||
|
|
abb3d2a8d9 | ||
|
|
637fe8a04b | ||
|
|
be321e95e5 | ||
|
|
ed46c1486c | ||
|
|
c9fcfc6862 | ||
|
|
8495e37566 |
2
.github/workflows/nodejs.yml
vendored
2
.github/workflows/nodejs.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x]
|
||||
node-version: [12.x, 14.x, 15.x]
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
||||
@@ -1 +1 @@
|
||||
v14.4.0
|
||||
v14.15.0
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
FROM node:14.4.0-alpine AS base
|
||||
FROM node:14.15.0-alpine AS base
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
RUN npm i -g npm@latest
|
||||
|
||||
WORKDIR /misskey
|
||||
|
||||
FROM base AS builder
|
||||
|
||||
@@ -174,6 +174,7 @@ imageUrl: "عنوان URL للصورة"
|
||||
remove: "حذف"
|
||||
removed: "تم حذفه بنجاح"
|
||||
removeAreYouSure: "متأكد من أنك تريد حذف {x}؟"
|
||||
deleteAreYouSure: "متأكد من أنك تريد حذف {x}؟"
|
||||
saved: "تم حفظه"
|
||||
messaging: "الدردشة"
|
||||
upload: "تحميل"
|
||||
|
||||
@@ -214,6 +214,8 @@ imageUrl: "Bild-URL"
|
||||
remove: "Löschen"
|
||||
removed: "Erfolgreich gelöscht"
|
||||
removeAreYouSure: "Möchtest du \"{x}\" wirklich löschen?"
|
||||
deleteAreYouSure: "Möchtest du \"{x}\" wirklich löschen?"
|
||||
resetAreYouSure: "Wirklich zurücksetzen?"
|
||||
saved: "Gespeichert"
|
||||
messaging: "Chat"
|
||||
upload: "Hochladen"
|
||||
@@ -604,13 +606,53 @@ system: "System"
|
||||
switchUi: "UI wechseln"
|
||||
desktop: "Desktop"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Spickzettel"
|
||||
intro: "MFM ist eine an vielen Stellen verwendbare und Misskey-exklusive Markup-Sprache. Hier kannst du eine Liste von verfügbarer MFM-Syntax anschauen."
|
||||
dummy: "Misskey erweitert die Welt des Fediverse"
|
||||
mention: "Erwähnung"
|
||||
mentionDescription: "Mit At-Zeichen und Nutzername kann ein individueller Nutzer angegeben werden."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Mit einer Raute und Text kann ein Hashtag angegeben werden."
|
||||
url: "URL"
|
||||
urlDescription: "URLs können angezeigt werden."
|
||||
link: "Link"
|
||||
center: "Bestandteile zentrieren"
|
||||
quote: "Zitieren"
|
||||
linkDescription: "Ein spezifizierter Textabschnitt kann als URL angezeigt werden."
|
||||
bold: "Fett"
|
||||
boldDescription: "Zeichen zur Betonung dicker erscheinen lassen."
|
||||
small: "Klein"
|
||||
smallDescription: "Inhalt klein und dünn erscheinen lassen."
|
||||
center: "Zentrieren"
|
||||
centerDescription: "Inhalt zentriert anzeigen lassen."
|
||||
inlineCode: "Code (Eingebettet)"
|
||||
inlineCodeDescription: "Syntax-Hervorhebung für (Programm-)Code eingebettet anzeigen lassen."
|
||||
blockCode: "Code (Block)"
|
||||
blockCodeDescription: "Syntax-Hervorhebung für mehrzeiligen (Programm-)Code als Block anzeigen lassen."
|
||||
inlineMath: "Mathe (Eingebettet)"
|
||||
inlineMathDescription: "Mathematische Formeln (KaTeX) eingebettet anzeigen."
|
||||
blockMath: "Mathe (Block)"
|
||||
blockMathDescription: "Mehrzeilige mathematische Formeln (KaTeX) als Block einbetten."
|
||||
quote: "Zitationen"
|
||||
quoteDescription: "Inhalt als Zitat anzeigen lassen."
|
||||
emoji: "Benutzerdefinierte Emojis"
|
||||
search: "Suchen"
|
||||
emojiDescription: "Emoji-Namen mit Doppelpunkten umschließen, um benutzerdefinierte Emojis anzeigen zu lassen."
|
||||
search: "Suche"
|
||||
searchDescription: "Eine vorgefertige Suchanfragebox anzeigen lassen."
|
||||
flip: "Spiegelung"
|
||||
flipDescription: "Inhalt horizontal oder vertikal gespiegelt anzeigen lassen."
|
||||
jelly: "Animation (Dehnen)"
|
||||
jellyDescription: "Verleiht eine sich dehnende Animation."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Verleiht eine Animation mit \"Tada!\"-Gefühl"
|
||||
jump: "Animation (Sprung)"
|
||||
jumpDescription: "Verleiht eine springende Animation."
|
||||
bounce: "Animation (Federn)"
|
||||
bounceDescription: "Erzeugt eine federnde Animation."
|
||||
shake: "Animation (Zittern)"
|
||||
shakeDescription: "Verleiht eine zitternde Animation."
|
||||
twitch: "Animation (Zucken)"
|
||||
twitchDescription: "Verleiht eine sehr stark zuckende Animation."
|
||||
spin: "Animation (Rotieren)"
|
||||
spinDescription: "Verleiht eine rotierende Animation."
|
||||
_reversi:
|
||||
reversi: "Reversi"
|
||||
gameSettings: "Spieleinstellungen"
|
||||
@@ -1039,6 +1081,7 @@ _pages:
|
||||
my: "Meine Seiten"
|
||||
liked: "Seiten, die mir gefallen"
|
||||
inspector: "Inspektor"
|
||||
contents: "Inhalt"
|
||||
content: "Inhalt"
|
||||
variables: "Variablen"
|
||||
title: "Titel"
|
||||
|
||||
@@ -214,6 +214,8 @@ imageUrl: "Image URL"
|
||||
remove: "Delete"
|
||||
removed: "Successfully deleted"
|
||||
removeAreYouSure: "Are you sure that you want to delete \"{x}\"?"
|
||||
deleteAreYouSure: "Are you sure that you want to delete \"{x}\"?"
|
||||
resetAreYouSure: "Really reset?"
|
||||
saved: "Saved"
|
||||
messaging: "Messaging"
|
||||
upload: "Upload"
|
||||
@@ -604,13 +606,53 @@ system: "System"
|
||||
switchUi: "Switch UI"
|
||||
desktop: "Desktop"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM is a Misskey-exclusive markup language that can be used in many places. Here you can view a list of all available MFM syntax."
|
||||
dummy: "Misskey expands the world of the Fediverse"
|
||||
mention: "Mention"
|
||||
mentionDescription: "Using an At-Symbol and a username, you can specify a specific user."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Using a number sign and text, you can specify a hashtag."
|
||||
url: "URL"
|
||||
urlDescription: "URLs can be displayed."
|
||||
link: "Link"
|
||||
center: "Center elements"
|
||||
linkDescription: "Specific parts of text can be displayed as URL."
|
||||
bold: "Bold"
|
||||
boldDescription: "Highlights letters by making them thicker."
|
||||
small: "Small"
|
||||
smallDescription: "Displays contents small and thinn."
|
||||
center: "Center"
|
||||
centerDescription: "Displays content centered."
|
||||
inlineCode: "Code (Inline)"
|
||||
inlineCodeDescription: "Displays inline syntax highlighting for (program-)code."
|
||||
blockCode: "Code (Block)"
|
||||
blockCodeDescription: "Displays syntax highlighting for multi-line (program-)code in a block."
|
||||
inlineMath: "Math (In-line)"
|
||||
inlineMathDescription: "Display math formulas (KaTeX) in-line"
|
||||
blockMath: "Math (Block)"
|
||||
blockMathDescription: "Display multi-line Math formulas (KaTeX) in a block"
|
||||
quote: "Quote"
|
||||
quoteDescription: "Displays content as quote."
|
||||
emoji: "Custom Emoji"
|
||||
emojiDescription: "By surrounding a custom emoji name with colons, custom emoji can be displayed."
|
||||
search: "Search"
|
||||
searchDescription: "Displays a search box with pre-entered text."
|
||||
flip: "Flip"
|
||||
flipDescription: "Flips content horizontally or vertically."
|
||||
jelly: "Animation (Jelly)"
|
||||
jellyDescription: "Infuses a jelly-like animation."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Infuses a \"Tada!\"-like animation."
|
||||
jump: "Animation (Jump)"
|
||||
jumpDescription: "Infuses a jumping animation."
|
||||
bounce: "Animation (Bounce)"
|
||||
bounceDescription: "Causes a bouncy animation."
|
||||
shake: "Animation (Shake)"
|
||||
shakeDescription: "Infuses a shaking animation."
|
||||
twitch: "Animation (Twitch)"
|
||||
twitchDescription: "Infuses a strongly twitching animation."
|
||||
spin: "Animation (Spin)"
|
||||
spinDescription: "Infuses a spinning animation."
|
||||
_reversi:
|
||||
reversi: "Reversi"
|
||||
gameSettings: "Game settings"
|
||||
@@ -1039,6 +1081,7 @@ _pages:
|
||||
my: "My pages"
|
||||
liked: "Liked pages"
|
||||
inspector: "Inspector"
|
||||
contents: "Content"
|
||||
content: "Page block"
|
||||
variables: "Variables"
|
||||
title: "Title"
|
||||
|
||||
@@ -214,6 +214,7 @@ imageUrl: "URL de la imágen"
|
||||
remove: "Borrar"
|
||||
removed: "Borrado"
|
||||
removeAreYouSure: "¿Desea borrar \"{x}\"?"
|
||||
deleteAreYouSure: "¿Desea borrar \"{x}\"?"
|
||||
saved: "Guardado"
|
||||
messaging: "Chat"
|
||||
upload: "Subir"
|
||||
@@ -540,6 +541,7 @@ pluginInstallWarn: "Por favor no instale plugins que no son de confianza"
|
||||
deck: "Deck"
|
||||
undeck: "Quitar deck"
|
||||
useBlurEffectForModal: "Usar efecto borroso en modales"
|
||||
useFullReactionPicker: "Reacción"
|
||||
generateAccessToken: "Generar token de acceso"
|
||||
permission: "Permisos"
|
||||
enableAll: "Activar todo"
|
||||
@@ -603,13 +605,22 @@ system: "Sistema"
|
||||
switchUi: "Cambiar interfaz de usuario"
|
||||
desktop: "Escritorio"
|
||||
_mfm:
|
||||
cheatSheet: "Hoja de referencia de MFM"
|
||||
intro: "MFM es un lenguaje de marcado dedicado que se puede usar en varios lugares dentro de Misskey. Aquí puede ver una lista de sintaxis disponibles en MFM."
|
||||
mention: "Menciones"
|
||||
mentionDescription: "El signo @ seguido de un nombre de usuario se puede utilizar para notificar a un usuario en particular."
|
||||
hashtag: "Hashtag"
|
||||
url: "URL"
|
||||
link: "Vínculo"
|
||||
bold: "Negrita"
|
||||
center: "Centrar"
|
||||
blockCode: "Código (bloque)"
|
||||
blockCodeDescription: "Código de resaltado de sintaxis, como programas de varias líneas con bloques."
|
||||
quote: "Citar"
|
||||
emoji: "Emojis personalizados"
|
||||
search: "Buscar"
|
||||
flip: "Echar de un capirotazo"
|
||||
flipDescription: "Voltea el contenido hacia arriba / abajo o hacia la izquierda / derecha."
|
||||
_reversi:
|
||||
reversi: "Reversi"
|
||||
gameSettings: "Configuración del juego"
|
||||
@@ -1038,6 +1049,7 @@ _pages:
|
||||
my: "Mis páginas"
|
||||
liked: "Páginas que me gustan"
|
||||
inspector: "Inspector"
|
||||
contents: "Contenido"
|
||||
content: "Bloque de página"
|
||||
variables: "Variables"
|
||||
title: "Título"
|
||||
|
||||
@@ -213,6 +213,7 @@ imageUrl: "URL de l’image"
|
||||
remove: "Supprimer"
|
||||
removed: "Supprimé"
|
||||
removeAreYouSure: "Supprimer «{x}» ?"
|
||||
deleteAreYouSure: "Supprimer «{x}» ?"
|
||||
saved: "Enregistré"
|
||||
messaging: "Discuter"
|
||||
upload: "Téléverser"
|
||||
@@ -939,6 +940,7 @@ _pages:
|
||||
my: "Mes pages"
|
||||
liked: "Pages favorites"
|
||||
inspector: "Inspecteur"
|
||||
contents: "Contenu"
|
||||
content: "Bloc de page"
|
||||
variables: "Variables"
|
||||
title: "Titre"
|
||||
|
||||
@@ -95,6 +95,7 @@ sensitive: "閲覧注意"
|
||||
add: "追加"
|
||||
reaction: "リアクション"
|
||||
reactionSettingDescription: "リアクションピッカーに表示するリアクションを設定します。"
|
||||
reactionSettingDescription2: "ドラッグして並び替えます。クリックして削除します。"
|
||||
rememberNoteVisibility: "公開範囲を記憶する"
|
||||
attachCancel: "添付取り消し"
|
||||
markAsSensitive: "閲覧注意にする"
|
||||
@@ -214,6 +215,8 @@ imageUrl: "画像URL"
|
||||
remove: "削除"
|
||||
removed: "削除しました"
|
||||
removeAreYouSure: "「{x}」を削除しますか?"
|
||||
deleteAreYouSure: "「{x}」を削除しますか?"
|
||||
resetAreYouSure: "リセットしますか?"
|
||||
saved: "保存しました"
|
||||
messaging: "チャット"
|
||||
upload: "アップロード"
|
||||
@@ -603,6 +606,9 @@ random: "ランダム"
|
||||
system: "システム"
|
||||
switchUi: "UI切り替え"
|
||||
desktop: "デスクトップ"
|
||||
clip: "クリップ"
|
||||
createNew: "新規作成"
|
||||
optional: "任意"
|
||||
|
||||
_mfm:
|
||||
cheatSheet: "MFMチートシート"
|
||||
@@ -1098,6 +1104,7 @@ _pages:
|
||||
created: "ページを作成しました"
|
||||
updated: "ページを更新しました"
|
||||
deleted: "ページを削除しました"
|
||||
pageSetting: "ページ設定"
|
||||
nameAlreadyExists: "指定されたページURLは既に存在しています"
|
||||
invalidNameTitle: "不正なページURLです"
|
||||
invalidNameText: "空白でないか確認してください"
|
||||
@@ -1109,6 +1116,7 @@ _pages:
|
||||
my: "自分のページ"
|
||||
liked: "いいねしたページ"
|
||||
inspector: "インスペクター"
|
||||
contents: "コンテンツ"
|
||||
content: "ページブロック"
|
||||
variables: "変数"
|
||||
title: "タイトル"
|
||||
@@ -1169,6 +1177,12 @@ _pages:
|
||||
width: "幅"
|
||||
height: "高さ"
|
||||
|
||||
note: "ノート埋め込み"
|
||||
_note:
|
||||
id: "ノートID"
|
||||
idDescription: "ノートURLをペーストして設定することもできます。"
|
||||
detailed: "詳細な表示"
|
||||
|
||||
switch: "スイッチ"
|
||||
_switch:
|
||||
name: "変数名"
|
||||
|
||||
@@ -214,6 +214,7 @@ imageUrl: "画像URL"
|
||||
remove: "ほかす"
|
||||
removed: "削除したで!"
|
||||
removeAreYouSure: "「{x}」はなおしてしもてええか?"
|
||||
deleteAreYouSure: "「{x}」はなおしてしもてええか?"
|
||||
saved: "保存したで!"
|
||||
messaging: "チャット"
|
||||
upload: "アップロード"
|
||||
|
||||
@@ -57,6 +57,7 @@ _exportOrImport:
|
||||
blockingList: "Seḥbes"
|
||||
userLists: "Tibdarin"
|
||||
_pages:
|
||||
contents: "Agbur"
|
||||
font: "Tasefsit"
|
||||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
|
||||
@@ -204,6 +204,7 @@ imageUrl: "이미지 URL"
|
||||
remove: "삭제"
|
||||
removed: "삭제하였습니다"
|
||||
removeAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?"
|
||||
deleteAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?"
|
||||
saved: "저장하였습니다"
|
||||
messaging: "대화"
|
||||
upload: "업로드"
|
||||
@@ -888,6 +889,7 @@ _pages:
|
||||
my: "내 페이지"
|
||||
liked: "좋아요한 페이지"
|
||||
inspector: "인스펙터"
|
||||
contents: "콘텐츠"
|
||||
content: "페이지 블록"
|
||||
variables: "변수"
|
||||
title: "제목"
|
||||
|
||||
@@ -11,7 +11,7 @@ ok: "Окей"
|
||||
gotIt: "Ясно!"
|
||||
cancel: "Отмена"
|
||||
enterUsername: "Введите имя пользователя"
|
||||
renotedBy: "{user} передаёт"
|
||||
renotedBy: "{user} делится"
|
||||
noNotes: "Нет ни одной заметки"
|
||||
noNotifications: "Нет ни одного уведомления"
|
||||
instance: "Инстанс"
|
||||
@@ -214,6 +214,8 @@ imageUrl: "Ссылка на изображение"
|
||||
remove: "Удалить"
|
||||
removed: "Удалено"
|
||||
removeAreYouSure: "Хотите удалить «{x}»?"
|
||||
deleteAreYouSure: "Хотите удалить «{x}»?"
|
||||
resetAreYouSure: "На самом деле сбросить?"
|
||||
saved: "Сохранено"
|
||||
messaging: "Сообщения"
|
||||
upload: "Загрузить"
|
||||
@@ -266,7 +268,7 @@ unableToDelete: "Удаление невозможно"
|
||||
inputNewFileName: "Введите имя нового файла"
|
||||
inputNewFolderName: "Пожалуйста, введите новое имя папки!"
|
||||
circularReferenceFolder: "Вы пытаетесь переместить папку внутрь себя."
|
||||
hasChildFilesOrFolders: "В этой папке что-то есть, так что она не может быть удалена."
|
||||
hasChildFilesOrFolders: "Эта папка не пуста и не может быть удалена."
|
||||
copyUrl: "Копировать ссылку"
|
||||
rename: "Переименовать"
|
||||
avatar: "Аватар"
|
||||
@@ -604,13 +606,53 @@ system: "Система"
|
||||
switchUi: "Выбор вида"
|
||||
desktop: "Стол"
|
||||
_mfm:
|
||||
cheatSheet: "Подсказка по разметке MFM"
|
||||
intro: "MFM — язык оформления текста, придуманный специально для Misskey, который здесь можно много где использовать. На этой странице собраны и кратко изложены способы его применения."
|
||||
dummy: "Misskey расширяет границы Федиверса."
|
||||
mention: "Упоминание"
|
||||
mentionDescription: "При помощи знака «собака» перед именем можно упомянуть какого-нибудь пользователя."
|
||||
hashtag: "Хэштег"
|
||||
link: "Ссылка"
|
||||
hashtagDescription: "При помощи знака «решётка» перед словом задаётся хэштег."
|
||||
url: "Простая ссылка (URL)"
|
||||
urlDescription: "Ссылки могут отображаться непосредственно."
|
||||
link: "Ссылка с пояснением"
|
||||
linkDescription: "Можно ссылку оформить в виде произвольного текста."
|
||||
bold: "Жирный шрифт"
|
||||
boldDescription: "Выделяет текст, делая буквы жирнее."
|
||||
small: "Мелкий шрифт"
|
||||
smallDescription: "Делает текст маленьким и незаметным."
|
||||
center: "Выровнять элементы по центру"
|
||||
centerDescription: "Так можно выровнять что-то по центру."
|
||||
inlineCode: "Программа (в тексте)"
|
||||
inlineCodeDescription: "Подсвечивает фрагмент программы внутри сплошного текста."
|
||||
blockCode: "Программа (блок)"
|
||||
blockCodeDescription: "Оформляет текст программы в виде отдельного блокоа. Он может состоять из множества строк."
|
||||
inlineMath: "Математическое выражение (в тексте)"
|
||||
inlineMathDescription: "Позволяет вставлять математические выражения внутрь текста при помощи языка KaTeX."
|
||||
blockMath: "Математическое выражение (блок)"
|
||||
blockMathDescription: "Оформляет математическое выражение (KaTeX) на отдельной строке."
|
||||
quote: "Цитата"
|
||||
quoteDescription: "Так можно процитировать чей-то текст."
|
||||
emoji: "Эмодзи пользователя"
|
||||
emojiDescription: "Можно вставить эмодзи в текст, окружив название двоеточиями."
|
||||
search: "Поиск"
|
||||
searchDescription: "Можно добавить форму для поиска, сразу задав, что искать."
|
||||
flip: "Переворот"
|
||||
flipDescription: "Позволяет отразить текст зеркально по вертикали или горизонтали."
|
||||
jelly: "Анимация желе (шлёп-плёп)"
|
||||
jellyDescription: "Напоминает горку джема, дёргающуюся от шлепков."
|
||||
tada: "Анимация (та-дам!)"
|
||||
tadaDescription: "Получается нечто выпрыгивающее, как бы крича: «а вот и я!»"
|
||||
jump: "Анимация прыжков (прыг-скок)"
|
||||
jumpDescription: "Побуждает радостно подпрыгивать."
|
||||
bounce: "Анимация отскоков (бум-бум)"
|
||||
bounceDescription: "Это будет скакать как мяч."
|
||||
shake: "Анимация дрожи (б-р-р-р)"
|
||||
shakeDescription: "Такое дрожит, словно от холода. Или от страха."
|
||||
twitch: "Анимация тряски"
|
||||
twitchDescription: "Заставляет трястись как одержимого"
|
||||
spin: "Вращение"
|
||||
spinDescription: "Так можно крутить содержимое в разных направлениях."
|
||||
_reversi:
|
||||
reversi: "Реверси"
|
||||
gameSettings: "Настройки игры"
|
||||
@@ -1039,6 +1081,7 @@ _pages:
|
||||
my: "Свои страницы"
|
||||
liked: "Понравившиеся страницы"
|
||||
inspector: "Инспектор"
|
||||
contents: "Содержательные"
|
||||
content: "Содержимое"
|
||||
variables: "Переменные"
|
||||
title: "Заголовок"
|
||||
|
||||
@@ -5,6 +5,7 @@ search: "Пошук"
|
||||
notifications: "Сповіщення"
|
||||
username: "Ім'я користувача"
|
||||
password: "Пароль"
|
||||
fetchingAsApObject: "Отримуємо з федіверсу..."
|
||||
ok: "OK"
|
||||
gotIt: "Зрозуміло!"
|
||||
cancel: "Скасувати"
|
||||
@@ -110,6 +111,7 @@ editWidgetsExit: "Готово"
|
||||
customEmojis: "Кастомні емоджі"
|
||||
emoji: "Емоджі"
|
||||
emojiName: "Назва емоджі"
|
||||
emojiUrl: "URL емодзі"
|
||||
addEmoji: "Додати емодзі"
|
||||
settingGuide: "Рекомендована конфігурація"
|
||||
cacheRemoteFiles: "Кешувати дані з інших інстансів"
|
||||
@@ -141,6 +143,7 @@ storageUsage: "Використання простіру"
|
||||
charts: "Графіки"
|
||||
perHour: "Щогодини"
|
||||
perDay: "Щоденно"
|
||||
stopActivityDelivery: "Припинити розсилання активності"
|
||||
blockThisInstance: "Заблокувати цей інстанс"
|
||||
operations: "Операції"
|
||||
software: "Програмне забезпечення"
|
||||
@@ -155,7 +158,9 @@ disk: "Диск"
|
||||
instanceInfo: "Про цей інстанс"
|
||||
statistics: "Статистика"
|
||||
clearQueue: "Очистити чергу"
|
||||
clearQueueConfirmTitle: "Ви впевнені, що хочете очистити чергу?"
|
||||
clearCachedFiles: "Очистити кеш"
|
||||
clearCachedFilesConfirm: "Ви впевнені, що хочете видалити всі кешовані файли?"
|
||||
blockedInstances: "Заблоковані інстанси"
|
||||
muteAndBlock: "Ігнор і блокування"
|
||||
mutedUsers: "Ігноровані користувачі"
|
||||
@@ -172,6 +177,7 @@ noCustomEmojis: "Немає кастомних емоджі"
|
||||
noJobs: "Немає завдань"
|
||||
federating: "Федерується"
|
||||
blocked: "Заблоковано"
|
||||
suspended: "Призупинено"
|
||||
notResponding: "Не відповідає"
|
||||
changePassword: "Змінити пароль"
|
||||
security: "Безпека"
|
||||
@@ -195,7 +201,9 @@ fromUrl: "З URL"
|
||||
uploadFromUrl: "Завантажити з URL"
|
||||
explore: "Огляд"
|
||||
games: "Ігри Misskey"
|
||||
noMoreHistory: "Подальшої історії немає"
|
||||
start: "Розпочати"
|
||||
home: "Домівка"
|
||||
activity: "Активність"
|
||||
images: "Зображення"
|
||||
birthday: "День народження"
|
||||
@@ -221,17 +229,30 @@ createFolder: "Створити теку"
|
||||
renameFolder: "Перейменувати теку"
|
||||
deleteFolder: "Видалити теку"
|
||||
addFile: "Додати файл"
|
||||
emptyDrive: "Диск порожній"
|
||||
emptyFolder: "Тека порожня"
|
||||
unableToDelete: "Видалення неможливе"
|
||||
inputNewFileName: "Введіть ім'я нового файлу"
|
||||
inputNewFolderName: "Введіть ім'я нової теки"
|
||||
hasChildFilesOrFolders: "Ця тека не порожня і не може бути видалена"
|
||||
copyUrl: "Копіювати URL"
|
||||
rename: "Перейменувати"
|
||||
avatar: "Аватар"
|
||||
banner: "Банер"
|
||||
nsfw: "NSFW"
|
||||
disconnectedFromServer: "Підключення до сервера було перервано"
|
||||
reload: "Оновити"
|
||||
doNothing: "Нічого не робити"
|
||||
reloadConfirm: "Перезавантажити стрічку?"
|
||||
watch: "Стежити"
|
||||
unwatch: "Не стежити"
|
||||
accept: "Прийняти"
|
||||
reject: "Відхилити"
|
||||
instanceName: "Назва інстансу"
|
||||
instanceDescription: "Описання інстансу"
|
||||
maintainerName: "Ім'я адміністратора"
|
||||
maintainerEmail: "Email адміністратора"
|
||||
tosUrl: "URL умов використання"
|
||||
thisYear: "Рік"
|
||||
thisMonth: "Місяць"
|
||||
today: "День"
|
||||
@@ -239,19 +260,163 @@ dayX: "{day}"
|
||||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Сторінки"
|
||||
integration: "Інтеграція"
|
||||
connectSerice: "Під’єднатися"
|
||||
disconnectSerice: "Відключитися"
|
||||
enableLocalTimeline: "Увімкнути локальну стрічку"
|
||||
enableGlobalTimeline: "Увімкнути глобальну стрічку"
|
||||
registration: "Реєстрація"
|
||||
enableRegistration: "Дозволити реєстрацію"
|
||||
invite: "Запрошення"
|
||||
proxyRemoteFiles: "Проксувати файли з інших інстансів"
|
||||
iconUrl: "URL аватара"
|
||||
bannerUrl: "URL банера"
|
||||
basicInfo: "Основна інформація"
|
||||
pinnedUsers: "Закріплені користувачі"
|
||||
hcaptcha: "hCaptcha"
|
||||
enableHcaptcha: "Увімкнути hCaptcha"
|
||||
hcaptchaSiteKey: "Ключ сайту"
|
||||
hcaptchaSecretKey: "Секретний ключ"
|
||||
recaptcha: "reCAPTCHA"
|
||||
enableRecaptcha: "Увімкнути reCAPTCHA"
|
||||
recaptchaSiteKey: "Ключ сайту"
|
||||
recaptchaSecretKey: "Секретний ключ"
|
||||
antennas: "Антени"
|
||||
manageAntennas: "Налаштування антен"
|
||||
name: "Ім'я"
|
||||
antennaSource: "Джерело антени"
|
||||
antennaKeywords: "Ключові слова антени"
|
||||
antennaExcludeKeywords: "Винятки"
|
||||
serviceworker: "ServiceWorker"
|
||||
enableServiceworker: "Ввімкнути ServiceWorker"
|
||||
caseSensitive: "З урахуванням регістру"
|
||||
notesAndReplies: "Дописи та відповіді"
|
||||
popularUsers: "Популярні користувачі"
|
||||
recentlyUpdatedUsers: "Нещодавно активні користувачі"
|
||||
recentlyRegisteredUsers: "Нещодавно зареєстровані користувачі"
|
||||
recentlyDiscoveredUsers: "Нещодавно знайдені користувачі"
|
||||
exploreUsersCount: "{count} користувачів"
|
||||
exploreFediverse: "Огляд федіверсу"
|
||||
popularTags: "Популярні теги"
|
||||
userList: "Списки"
|
||||
about: "Інформація"
|
||||
aboutMisskey: "Про Misskey"
|
||||
administrator: "Адмін"
|
||||
token: "Токен"
|
||||
twoStepAuthentication: "Двохфакторна аутентифікація"
|
||||
moderator: "Модератор"
|
||||
securityKey: "Ключ захисту"
|
||||
securityKeyName: "Назва ключа"
|
||||
registerSecurityKey: "Зареєструвати ключ захисту"
|
||||
lastUsed: "Востаннє використано"
|
||||
unregister: "Скасувати реєстрацію"
|
||||
passwordLessLogin: "Налаштувати вхід без пароля"
|
||||
resetPassword: "Скинути пароль"
|
||||
newPasswordIs: "Новий пароль: {password}"
|
||||
share: "Поділитись"
|
||||
notFound: "Не знайдено"
|
||||
cacheClear: "Очистити кеш"
|
||||
help: "Допомога"
|
||||
inputMessageHere: "Введіть повідомлення тут"
|
||||
close: "Закрити"
|
||||
group: "Група"
|
||||
groups: "Групи"
|
||||
createGroup: "Створити групу"
|
||||
ownedGroups: "Власні групи"
|
||||
invites: "Запрошення"
|
||||
groupName: "Назва групи"
|
||||
transfer: "Передача"
|
||||
messagingWithUser: "Чат з користувачами"
|
||||
messagingWithGroup: "Чат з групою"
|
||||
title: "Тема"
|
||||
text: "Текст"
|
||||
next: "Далі"
|
||||
retype: "Введіть ще раз"
|
||||
noteOf: "Допис {user}"
|
||||
inviteToGroup: "Запрошення до групи"
|
||||
maxNoteTextLength: "Максимальна довжина допису"
|
||||
quoteAttached: "Цитата"
|
||||
quoteQuestion: "Ви хочете додати цитату?"
|
||||
noMessagesYet: "Ще немає повідомлень"
|
||||
newMessageExists: "Є нові повідомлення"
|
||||
onlyOneFileCanBeAttached: "До повідомлення можна вкласти лише один файл"
|
||||
signinRequired: "Будь ласка, авторизуйтесь"
|
||||
invitations: "Запрошення"
|
||||
invitationCode: "Код запрошення"
|
||||
checking: "Перевірка…"
|
||||
available: "Доступно"
|
||||
unavailable: "Недоступно"
|
||||
usernameInvalidFormat: "літери, цифри та _ є прийнятними"
|
||||
tooShort: "Занадто короткий"
|
||||
tooLong: "Занадто довгий"
|
||||
weakPassword: "Слабкий пароль"
|
||||
strongPassword: "Міцний пароль"
|
||||
passwordMatched: "Все вірно"
|
||||
passwordNotMatched: "Паролі не співпадають"
|
||||
signinWith: "Увійти за допомогою {x}"
|
||||
uiLanguage: "Мова інтерфейсу"
|
||||
aboutX: "Про {x}"
|
||||
useOsNativeEmojis: "Використовувати емодзі ОС"
|
||||
youHaveNoGroups: "Немає груп"
|
||||
noHistory: "Історія порожня"
|
||||
disableAnimatedMfm: "Відключити анімації MFM"
|
||||
doing: "Виконується"
|
||||
category: "Категорія"
|
||||
tags: "Теги"
|
||||
docSource: "Джерело цього документа"
|
||||
createAccount: "Створити акаунт"
|
||||
existingAcount: "Існуючий акаунт"
|
||||
regenerate: "Оновити"
|
||||
fontSize: "Розмір шрифту"
|
||||
noFollowRequests: "Немає запитів на підписку"
|
||||
dashboard: "Панель приладів"
|
||||
local: "Локальні"
|
||||
remote: "Віддалений"
|
||||
total: "Всього"
|
||||
appearance: "Вигляд"
|
||||
clientSettings: "Налаштування клієнта"
|
||||
accountSettings: "Налаштування акаунта"
|
||||
promotion: "Просування"
|
||||
promote: "Просунути"
|
||||
numberOfDays: "Кількість днів"
|
||||
hideThisNote: "Сховати цей допис"
|
||||
objectStorageBaseUrl: "Base URL"
|
||||
objectStorageBucket: "Bucket"
|
||||
objectStoragePrefix: "Prefix"
|
||||
objectStorageEndpoint: "Endpoint"
|
||||
objectStorageRegion: "Region"
|
||||
objectStorageUseSSL: "Використовувати SSL"
|
||||
objectStorageUseProxy: "Використовувати Proxy"
|
||||
deleteAll: "Видалити все"
|
||||
newNoteRecived: "Є нові дописи"
|
||||
sounds: "Звук"
|
||||
listen: "Слухати"
|
||||
showInPage: "Показати на сторінці"
|
||||
volume: "Гучність"
|
||||
install: "Інсталювати"
|
||||
uninstall: "Видалити"
|
||||
sort: "Сортування"
|
||||
ascendingOrder: "За зростанням"
|
||||
descendingOrder: "За спаданням"
|
||||
script: "Скрипт"
|
||||
deleteAllFiles: "Видалити всі файли"
|
||||
deleteAllFilesConfirm: "Ви дійсно хочете видалити всі файли?"
|
||||
sidebar: "Бокова панель"
|
||||
rooms: "Кімнати"
|
||||
relays: "Ретранслятори"
|
||||
addRelay: "Додати ретранслятор"
|
||||
smtpHost: "Хост"
|
||||
smtpUser: "Ім'я користувача"
|
||||
smtpPass: "Пароль"
|
||||
regenerateLoginToken: "Оновити Login Token"
|
||||
_mfm:
|
||||
cheatSheet: " Довідка MFM"
|
||||
mention: "Згадка"
|
||||
quote: "Цитата"
|
||||
emoji: "Кастомні емоджі"
|
||||
search: "Пошук"
|
||||
_reversi:
|
||||
total: "Всього"
|
||||
_sidebar:
|
||||
icon: "Аватар"
|
||||
_theme:
|
||||
@@ -272,17 +437,21 @@ _widgets:
|
||||
_cw:
|
||||
show: "Показати більше"
|
||||
_visibility:
|
||||
home: "Головна"
|
||||
home: "Домівка"
|
||||
followers: "Підписники"
|
||||
localOnly: "Лише локально"
|
||||
_postForm:
|
||||
replyPlaceholder: "Відповідь на допис..."
|
||||
_profile:
|
||||
name: "Ім'я"
|
||||
username: "Ім'я користувача"
|
||||
_exportOrImport:
|
||||
followingList: "Підписки"
|
||||
muteList: "Ігнорувати"
|
||||
blockingList: "Заблокувати"
|
||||
userLists: "Списки"
|
||||
_timelines:
|
||||
home: "Домівка"
|
||||
_rooms:
|
||||
_roomType:
|
||||
default: "За умовчанням"
|
||||
@@ -322,5 +491,6 @@ _deck:
|
||||
_columns:
|
||||
notifications: "Сповіщення"
|
||||
tl: "Стрічка"
|
||||
antenna: "Антени"
|
||||
list: "Списки"
|
||||
mentions: "Згадки"
|
||||
|
||||
@@ -84,7 +84,7 @@ followRequest: "关注申请"
|
||||
followRequests: "关注申请"
|
||||
unfollow: "取消关注"
|
||||
followRequestPending: "发送关注申请"
|
||||
enterEmoji: "输入Emoji"
|
||||
enterEmoji: "输入表情符号"
|
||||
renote: "转发"
|
||||
unrenote: "取消转发"
|
||||
quote: "引用"
|
||||
@@ -117,9 +117,9 @@ editWidgets: "编辑小工具"
|
||||
editWidgetsExit: "完成编辑"
|
||||
customEmojis: "自定义Emoji"
|
||||
emoji: "表情符号"
|
||||
emojiName: "Emoji 名称"
|
||||
emojiUrl: "emoji 地址"
|
||||
addEmoji: "添加Emoji"
|
||||
emojiName: "表情符号名称"
|
||||
emojiUrl: "表情符号地址"
|
||||
addEmoji: "添加表情符号"
|
||||
settingGuide: "推荐配置"
|
||||
cacheRemoteFiles: "远程文件缓存"
|
||||
cacheRemoteFilesDescription: "当禁用此设定时远程文件将直接从远程实例载入。禁用后会减小储存空间需求,但是会增加流量,因为缩略图不会被生成。"
|
||||
@@ -185,7 +185,7 @@ done: "完成"
|
||||
processing: "处理中"
|
||||
preview: "预览"
|
||||
default: "默认"
|
||||
noCustomEmojis: "无自定义Emoji"
|
||||
noCustomEmojis: "没有自定义表情符号"
|
||||
noJobs: "没有任务"
|
||||
federating: "联合中"
|
||||
blocked: "已拦截"
|
||||
@@ -214,6 +214,8 @@ imageUrl: "图片URL"
|
||||
remove: "删除"
|
||||
removed: "已删除"
|
||||
removeAreYouSure: "要删掉「{x}」吗?"
|
||||
deleteAreYouSure: "要删掉「{x}」吗?"
|
||||
resetAreYouSure: "恢复默认设置?"
|
||||
saved: "已保存"
|
||||
messaging: "聊天"
|
||||
upload: "上传"
|
||||
@@ -430,7 +432,7 @@ or: "或者"
|
||||
uiLanguage: "显示语言"
|
||||
groupInvited: "群组招待"
|
||||
aboutX: "关于 {x}"
|
||||
useOsNativeEmojis: "使用OS原生Emoji"
|
||||
useOsNativeEmojis: "使用OS原生表情符号"
|
||||
youHaveNoGroups: "没有群组"
|
||||
joinOrCreateGroup: "请加入一个现有的群组,或者创建新群组。"
|
||||
noHistory: "没有历史记录"
|
||||
@@ -549,7 +551,7 @@ tokenRequested: "允许访问账户"
|
||||
pluginTokenRequestedDescription: "此插件将能够拥有此处设置的权限"
|
||||
notificationType: "通知类型"
|
||||
edit: "编辑"
|
||||
useStarForReactionFallback: "如果回应的颜文字未知,则使用★作为代替"
|
||||
useStarForReactionFallback: "如果回应的是未知表情符号,则使用★作为代替"
|
||||
emailConfig: "邮件服务器设置"
|
||||
enableEmail: "启用发送邮件功能"
|
||||
emailConfigInfo: "用于确认电子邮件和密码重置"
|
||||
@@ -604,13 +606,53 @@ system: "系统"
|
||||
switchUi: "切换界面"
|
||||
desktop: "桌面"
|
||||
_mfm:
|
||||
cheatSheet: "MFM代码速查表"
|
||||
intro: "MFM是一种在Misskey中的各个位置使用的专用标记语言。在这里您可以看到MFM中可用的语法列表。"
|
||||
dummy: "通过Misskey扩展Fediverse的世界"
|
||||
mention: "提及"
|
||||
mentionDescription: "可以使用 @+用户名 来指示特定用户"
|
||||
hashtag: "话题标签"
|
||||
hashtagDescription: "可以使用井号+文字来表示话题标签。"
|
||||
url: "URL"
|
||||
urlDescription: "可以表示URL地址。"
|
||||
link: "链接"
|
||||
linkDescription: "可以将部分文字和URL关联起来。"
|
||||
bold: "粗体"
|
||||
boldDescription: "可以将文字显示为粗体来表示强调。"
|
||||
small: "缩小"
|
||||
smallDescription: "可以使内容文字变小、变淡。"
|
||||
center: "居中"
|
||||
centerDescription: "可以将内容居中显示。"
|
||||
inlineCode: "代码(内嵌)"
|
||||
inlineCodeDescription: "将文字中的程序代码语法高亮显示。"
|
||||
blockCode: "代码(块)"
|
||||
blockCodeDescription: "语法高亮显示整块程序代码。"
|
||||
inlineMath: "数学公式(内嵌)"
|
||||
inlineMathDescription: "显示内嵌的KaTex公式。"
|
||||
blockMath: "数学公式(块)"
|
||||
blockMathDescription: "显示整块的多行KaTex数学公式。"
|
||||
quote: "引用"
|
||||
emoji: "自定义Emoji"
|
||||
quoteDescription: "可以用来表示引用的内容。"
|
||||
emoji: "自定义表情符号"
|
||||
emojiDescription: "可以将自定义表情符号使用冒号括起来,就可以显示自定义表情符号了。"
|
||||
search: "搜索"
|
||||
searchDescription: "显示含有搜索内容示例的搜索框。"
|
||||
flip: "翻转"
|
||||
flipDescription: "将内容上下或左右翻转。"
|
||||
jelly: "动画(果冻)"
|
||||
jellyDescription: "显示果冻一样的动画效果。"
|
||||
tada: "动画(锵锵)"
|
||||
tadaDescription: "显示\"锵锵!\"的动画效果。"
|
||||
jump: "动画(跳动)"
|
||||
jumpDescription: "显示跳动的动画效果。"
|
||||
bounce: "动画(弹性)"
|
||||
bounceDescription: "显示弹性一样的动画效果。"
|
||||
shake: "动画(摇晃)"
|
||||
shakeDescription: "显示摇晃的动画效果。"
|
||||
twitch: "动画(颤抖)"
|
||||
twitchDescription: "显示强烈颤抖的动画效果。"
|
||||
spin: "动画(回转)"
|
||||
spinDescription: "显示回转的动画效果。"
|
||||
_reversi:
|
||||
reversi: "黑白棋"
|
||||
gameSettings: "对局设置"
|
||||
@@ -1039,6 +1081,7 @@ _pages:
|
||||
my: "我的页面"
|
||||
liked: "喜欢的页面"
|
||||
inspector: "检查器"
|
||||
contents: "内容"
|
||||
content: "页面内容"
|
||||
variables: "变量"
|
||||
title: "标题"
|
||||
|
||||
@@ -212,6 +212,7 @@ imageUrl: "圖片URL"
|
||||
remove: "刪除"
|
||||
removed: "成功移除"
|
||||
removeAreYouSure: "確定要刪掉「{x}」嗎?"
|
||||
deleteAreYouSure: "確定要刪掉「{x}」嗎?"
|
||||
saved: "已保存"
|
||||
messaging: "傳送訊息"
|
||||
upload: "上傳"
|
||||
|
||||
15
migration/1605408848373-clip-description.ts
Normal file
15
migration/1605408848373-clip-description.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class clipDescription1605408848373 implements MigrationInterface {
|
||||
name = 'clipDescription1605408848373'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "clip" ADD "description" character varying(2048) DEFAULT null`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
|
||||
await queryRunner.query(`ALTER TABLE "clip" DROP COLUMN "description"`);
|
||||
}
|
||||
|
||||
}
|
||||
434
migration/1605408971051-comments.ts
Normal file
434
migration/1605408971051-comments.ts
Normal file
@@ -0,0 +1,434 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class comments1605408971051 implements MigrationInterface {
|
||||
name = 'comments1605408971051'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`COMMENT ON COLUMN "log"."createdAt" IS 'The created date of the Log.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."createdAt" IS 'The created date of the DriveFolder.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."name" IS 'The name of the DriveFolder.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."parentId" IS 'The parent folder ID. If null, it means the DriveFolder is located in root.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."createdAt" IS 'The created date of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."userHost" IS 'The host of owner. It will be null if the user in local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."md5" IS 'The MD5 hash of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."name" IS 'The file name of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."type" IS 'The content type (MIME) of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."size" IS 'The file size (bytes) of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."comment" IS 'The comment of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."blurhash" IS 'The BlurHash string.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."properties" IS 'The any properties of the DriveFile. For example, it includes image width/height.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."thumbnailUrl" IS 'The URL of the thumbnail of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."webpublicUrl" IS 'The URL of the webpublic of the DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."folderId" IS 'The parent folder ID. If null, it means the DriveFile is located in root.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."isSensitive" IS 'Whether the DriveFile is NSFW.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."isLink" IS 'Whether the DriveFile is direct link to remote server.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."createdAt" IS 'The created date of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."updatedAt" IS 'The updated date of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."username" IS 'The username of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."usernameLower" IS 'The username (lowercased) of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."name" IS 'The name of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."followersCount" IS 'The count of followers.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."followingCount" IS 'The count of following.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."notesCount" IS 'The count of notes.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."avatarId" IS 'The ID of avatar DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."bannerId" IS 'The ID of banner DriveFile.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isSuspended" IS 'Whether the User is suspended.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isSilenced" IS 'Whether the User is silenced.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isLocked" IS 'Whether the User is locked.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isBot" IS 'Whether the User is a bot.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isCat" IS 'Whether the User is a cat.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isAdmin" IS 'Whether the User is the admin.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isModerator" IS 'Whether the User is a moderator.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."host" IS 'The host of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."inbox" IS 'The inbox URL of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."sharedInbox" IS 'The sharedInbox URL of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."featured" IS 'The featured URL of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."uri" IS 'The URI of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."token" IS 'The native access token of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."createdAt" IS 'The created date of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."secret" IS 'The secret key of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."name" IS 'The name of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."description" IS 'The description of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."permission" IS 'The permission of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."callbackUrl" IS 'The callbackUrl of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."createdAt" IS 'The created date of the AccessToken.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."lastUsedAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."session" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."appId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."iconUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."createdAt" IS 'The created date of the Channel.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."name" IS 'The name of the Channel.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."description" IS 'The description of the Channel.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."bannerId" IS 'The ID of banner Channel.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."notesCount" IS 'The count of notes.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."usersCount" IS 'The count of users.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."createdAt" IS 'The created date of the Note.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."replyId" IS 'The ID of reply target.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."renoteId" IS 'The ID of renote target.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."userId" IS 'The ID of author.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."uri" IS 'The URI of a note. it will be null when the note is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."url" IS 'The human readable url of a note. it will be null when the note is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."channelId" IS 'The ID of source channel.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."userHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."replyUserId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."replyUserHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."renoteUserId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."renoteUserHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll_vote"."createdAt" IS 'The created date of the PollVote.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_reaction"."createdAt" IS 'The created date of the NoteReaction.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."createdAt" IS 'The created date of the NoteWatching.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."userId" IS 'The watcher ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."noteId" IS 'The target Note ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."noteUserId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_unread"."noteUserId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_unread"."noteChannelId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."createdAt" IS 'The created date of the FollowRequest.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeId" IS 'The followee user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerId" IS 'The follower user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."requestId" IS 'id of Follow Activity.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerSharedInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeSharedInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group"."createdAt" IS 'The created date of the UserGroup.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group"."userId" IS 'The ID of owner.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_invitation"."createdAt" IS 'The created date of the UserGroupInvitation.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_invitation"."userId" IS 'The user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_invitation"."userGroupId" IS 'The group ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "notification"."createdAt" IS 'The created date of the Notification.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "notification"."notifieeId" IS 'The ID of recipient user of the Notification.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS 'Whether the Notification is read.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "meta"."localDriveCapacityMb" IS 'Drive capacity of a local user (MB)'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "meta"."remoteDriveCapacityMb" IS 'Drive capacity of a remote user (MB)'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "meta"."maxNoteTextLength" IS 'Max allowed note text length in characters'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."createdAt" IS 'The created date of the Following.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeId" IS 'The followee user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerId" IS 'The follower user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerSharedInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeSharedInbox" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."caughtAt" IS 'The caught date of the Instance.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."host" IS 'The host of the Instance.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."usersCount" IS 'The count of the users of the Instance.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."notesCount" IS 'The count of the notes of the Instance.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."softwareName" IS 'The software of the Instance.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."softwareVersion" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."openRegistrations" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."maintainerName" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."maintainerEmail" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."iconUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."faviconUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."themeColor" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muting"."createdAt" IS 'The created date of the Muting.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muting"."muteeId" IS 'The mutee user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muting"."muterId" IS 'The muter user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "blocking"."createdAt" IS 'The created date of the Blocking.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "blocking"."blockeeId" IS 'The blockee user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "blocking"."blockerId" IS 'The blocker user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list"."createdAt" IS 'The created date of the UserList.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list"."name" IS 'The name of the UserList.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list_joining"."createdAt" IS 'The created date of the UserListJoining.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list_joining"."userId" IS 'The user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list_joining"."userListId" IS 'The list ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_joining"."createdAt" IS 'The created date of the UserGroupJoining.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_joining"."userId" IS 'The user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_joining"."userGroupId" IS 'The group ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_favorite"."createdAt" IS 'The created date of the NoteFavorite.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "abuse_user_report"."createdAt" IS 'The created date of the AbuseUserReport.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "abuse_user_report"."targetUserHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "abuse_user_report"."reporterHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."createdAt" IS 'The created date of the MessagingMessage.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."userId" IS 'The sender user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."groupId" IS 'The recipient group ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "signin"."createdAt" IS 'The created date of the Signin.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "auth_session"."createdAt" IS 'The created date of the AuthSession.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."createdAt" IS 'The created date of the ReversiGame.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."startedAt" IS 'The started date of the ReversiGame.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."form1" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."form2" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_matching"."createdAt" IS 'The created date of the ReversiMatching.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_note_pining"."createdAt" IS 'The created date of the UserNotePinings.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."noteVisibility" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."userId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."userHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_keypair"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_publickey"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "page"."createdAt" IS 'The created date of the Page.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "page"."updatedAt" IS 'The updated date of the Page.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "page"."userId" IS 'The ID of author.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."location" IS 'The location of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."birthday" IS 'The birthday (YYYY-MM-DD) of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."description" IS 'The description (bio) of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."url" IS 'Remote URL of the user.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."email" IS 'The email address of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."password" IS 'The password hash of the User. It will be null if the origin of the user is local.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."clientData" IS 'The client-specific data of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."room" IS 'The room data of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."userHost" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."id" IS 'Variable-length id given to navigator.credentials.get()'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."publicKey" IS 'Variable-length public key used to verify attestations (hex-encoded).'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."lastUsed" IS 'The date of the last time the UserSecurityKey was successfully validated.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."name" IS 'User-defined name for this key'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "attestation_challenge"."challenge" IS 'Hex-encoded sha256 hash of the challenge.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "attestation_challenge"."createdAt" IS 'The date challenge was created for expiry purposes.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "attestation_challenge"."registrationChallenge" IS 'Indicates that the challenge is only for registration purposes if true to prevent the challenge for being used as authentication.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "moderation_log"."createdAt" IS 'The created date of the ModerationLog.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "announcement"."createdAt" IS 'The created date of the Announcement.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "announcement"."updatedAt" IS 'The updated date of the Announcement.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "announcement_read"."createdAt" IS 'The created date of the AnnouncementRead.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."createdAt" IS 'The created date of the Clip.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."name" IS 'The name of the Clip.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."description" IS 'The description of the Clip.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip_note"."noteId" IS 'The note ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip_note"."clipId" IS 'The clip ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna"."createdAt" IS 'The created date of the Antenna.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna"."userId" IS 'The owner ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna"."name" IS 'The name of the Antenna.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna_note"."noteId" IS 'The note ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna_note"."antennaId" IS 'The antenna ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "promo_note"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "promo_note"."userId" IS '[Denormalized]'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "promo_read"."createdAt" IS 'The created date of the PromoRead.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muted_note"."noteId" IS 'The note ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muted_note"."userId" IS 'The user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muted_note"."reason" IS 'The reason of the MutedNote.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_following"."createdAt" IS 'The created date of the ChannelFollowing.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_following"."followeeId" IS 'The followee channel ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_following"."followerId" IS 'The follower user ID.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_note_pining"."createdAt" IS 'The created date of the ChannelNotePining.'`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_note_pining"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_following"."followerId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_following"."followeeId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel_following"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muted_note"."reason" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muted_note"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muted_note"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "promo_read"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "promo_note"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "promo_note"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna_note"."antennaId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna_note"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "antenna"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip_note"."clipId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip_note"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "clip"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "announcement_read"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "announcement"."updatedAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "announcement"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "moderation_log"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "attestation_challenge"."registrationChallenge" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "attestation_challenge"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "attestation_challenge"."challenge" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."lastUsed" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."publicKey" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_security_key"."id" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."userHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."room" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."clientData" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."password" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."email" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."url" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."description" IS 'The description (bio) of the User.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."birthday" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."location" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_profile"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "page"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "page"."updatedAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "page"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_publickey"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_keypair"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."userHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."noteVisibility" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_note_pining"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_matching"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."form2" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."form1" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."startedAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "auth_session"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "signin"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."groupId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "abuse_user_report"."reporterHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "abuse_user_report"."targetUserHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "abuse_user_report"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_favorite"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_joining"."userGroupId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_joining"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_joining"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list_joining"."userListId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list_joining"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list_joining"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_list"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "blocking"."blockerId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "blocking"."blockeeId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "blocking"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muting"."muterId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muting"."muteeId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "muting"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."themeColor" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."faviconUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."iconUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."maintainerEmail" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."maintainerName" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."openRegistrations" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."softwareVersion" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."softwareName" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."notesCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."usersCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."host" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "instance"."caughtAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeSharedInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerSharedInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followerId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."followeeId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "following"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "meta"."maxNoteTextLength" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "meta"."remoteDriveCapacityMb" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "meta"."localDriveCapacityMb" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "notification"."isRead" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "notification"."notifieeId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "notification"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_invitation"."userGroupId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_invitation"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group_invitation"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user_group"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeSharedInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerSharedInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."requestId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followerId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."followeeId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "follow_request"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_unread"."noteChannelId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_unread"."noteUserId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."noteUserId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."noteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_watching"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note_reaction"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "poll_vote"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."renoteUserHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."renoteUserId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."replyUserHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."replyUserId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."userHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."channelId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."url" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."uri" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."renoteId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."replyId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "note"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."usersCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."notesCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."bannerId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "channel"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."iconUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."appId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."session" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."lastUsedAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "access_token"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."callbackUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."permission" IS 'The permission of the App.'`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."description" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."secret" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "app"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."token" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."uri" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."featured" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."sharedInbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."inbox" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."host" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isModerator" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isAdmin" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isCat" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isBot" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isLocked" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isSilenced" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isSuspended" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."bannerId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."avatarId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."notesCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."followingCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."followersCount" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."usernameLower" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."username" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."updatedAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."isLink" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."isSensitive" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."folderId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."webpublicUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."thumbnailUrl" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."properties" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."blurhash" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."comment" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."size" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."type" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."md5" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."userHost" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."parentId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."userId" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."name" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "drive_folder"."createdAt" IS NULL`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "log"."createdAt" IS NULL`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.55.0",
|
||||
"version": "12.57.0",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -246,10 +246,10 @@
|
||||
"vue-json-pretty": "1.7.1",
|
||||
"vue-loader": "16.0.0-beta.8",
|
||||
"vue-prism-editor": "1.2.2",
|
||||
"vue-router": "4.0.0-beta.13",
|
||||
"vue-router": "4.0.0-rc.2",
|
||||
"vue-style-loader": "4.1.2",
|
||||
"vue-template-compiler": "2.6.12",
|
||||
"vuex": "4.0.0-beta.4",
|
||||
"vuex": "4.0.0-rc.1",
|
||||
"vuex-persistedstate": "3.1.0",
|
||||
"web-push": "3.4.4",
|
||||
"webpack": "5.4.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
|
||||
<div class="omfetrab _popup">
|
||||
<input ref="search" class="search" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()" autofocus>
|
||||
<div class="omfetrab _popup" :class="{ compact }">
|
||||
<input ref="search" class="search" :class="{ filled: q != null && q != '' }" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()">
|
||||
<div class="emojis">
|
||||
<section class="result">
|
||||
<div v-if="searchResultCustom.length > 0">
|
||||
@@ -30,7 +30,7 @@
|
||||
</section>
|
||||
|
||||
<div class="index">
|
||||
<section>
|
||||
<section v-if="showPinned">
|
||||
<div>
|
||||
<button v-for="emoji in pinned"
|
||||
class="_button"
|
||||
@@ -43,7 +43,7 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<header class="_acrylic"><Fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
|
||||
<header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $t('recentUsed') }}</header>
|
||||
<div>
|
||||
<button v-for="emoji in $store.state.device.recentlyUsedEmojis"
|
||||
class="_button"
|
||||
@@ -94,7 +94,7 @@
|
||||
import { defineComponent, markRaw } from 'vue';
|
||||
import { emojilist } from '../../misc/emojilist';
|
||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faClock, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
||||
import MkModal from '@/components/ui/modal.vue';
|
||||
import Particle from '@/components/particle.vue';
|
||||
@@ -109,7 +109,11 @@ export default defineComponent({
|
||||
src: {
|
||||
required: false
|
||||
},
|
||||
overridePinned: {
|
||||
showPinned: {
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
compact: {
|
||||
required: false
|
||||
},
|
||||
},
|
||||
@@ -120,14 +124,14 @@ export default defineComponent({
|
||||
return {
|
||||
emojilist: markRaw(emojilist),
|
||||
getStaticImageUrl,
|
||||
pinned: this.overridePinned || this.$store.state.settings.reactions,
|
||||
pinned: this.$store.state.settings.reactions,
|
||||
customEmojiCategories: this.$store.getters['instance/emojiCategories'],
|
||||
customEmojis: this.$store.state.instance.meta.emojis,
|
||||
visibleCategories: {},
|
||||
q: null,
|
||||
searchResultCustom: [],
|
||||
searchResultUnicode: [],
|
||||
faGlobe, faHistory, faChevronDown,
|
||||
faGlobe, faClock, faChevronDown,
|
||||
categories: [{
|
||||
name: 'face',
|
||||
icon: faLaugh,
|
||||
@@ -311,9 +315,12 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const isIos = navigator.userAgent.includes('WebKit') && !navigator.userAgent.includes('Chrome');
|
||||
if (!isIos) {
|
||||
this.$refs.search.focus({
|
||||
preventScroll: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -379,8 +386,19 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.omfetrab {
|
||||
width: 350px;
|
||||
$eachSize: 40px;
|
||||
$pad: 8px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: ($eachSize * 7) + ($pad * 2);
|
||||
contain: content;
|
||||
--height: 300px;
|
||||
|
||||
&.compact {
|
||||
width: ($eachSize * 5) + ($pad * 2);
|
||||
--height: 210px;
|
||||
}
|
||||
|
||||
> .search {
|
||||
width: 100%;
|
||||
@@ -391,17 +409,27 @@ export default defineComponent({
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
|
||||
&:not(.filled) {
|
||||
order: 1;
|
||||
z-index: 2;
|
||||
box-shadow: 0px -1px 0 0px var(--divider);
|
||||
}
|
||||
}
|
||||
|
||||
> .emojis {
|
||||
$height: 300px;
|
||||
|
||||
height: $height;
|
||||
height: var(--height);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .index {
|
||||
min-height: $height;
|
||||
min-height: var(--height);
|
||||
position: relative;
|
||||
border-bottom: solid 1px var(--divider);
|
||||
|
||||
@@ -428,45 +456,33 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
> div {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||
gap: 4px;
|
||||
padding: 8px;
|
||||
padding: $pad;
|
||||
|
||||
> button {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
width: $eachSize;
|
||||
height: $eachSize;
|
||||
border-radius: 4px;
|
||||
|
||||
&:focus {
|
||||
outline: solid 2px var(--focus);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 0;
|
||||
padding-bottom: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
> * {
|
||||
transform: scale(1.2);
|
||||
transition: transform 0s;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--accent);
|
||||
box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15);
|
||||
}
|
||||
|
||||
> * {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
font-size: 28px;
|
||||
transition: transform 0.2s ease;
|
||||
font-size: 24px;
|
||||
height: 1.25em;
|
||||
vertical-align: -.25em;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@@ -474,6 +490,10 @@ export default defineComponent({
|
||||
|
||||
&.result {
|
||||
border-bottom: solid 1px var(--divider);
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.unicode {
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
<div class="xkpnjxcv _section">
|
||||
<label v-for="item in Object.keys(form).filter(item => !form[item].hidden)" :key="item">
|
||||
<MkInput v-if="form[item].type === 'number'" v-model:value="values[item]" type="number" :step="form[item].step || 1">
|
||||
<span v-text="form[item].label || item"></span>
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-else-if="form[item].type === 'string' && !item.multiline" v-model:value="values[item]" type="text">
|
||||
<span v-text="form[item].label || item"></span>
|
||||
<MkInput v-else-if="form[item].type === 'string' && !form[item].multiline" v-model:value="values[item]" type="text">
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</MkInput>
|
||||
<MkTextarea v-else-if="form[item].type === 'string' && item.multiline" v-model:value="values[item]">
|
||||
<span v-text="form[item].label || item"></span>
|
||||
<MkTextarea v-else-if="form[item].type === 'string' && form[item].multiline" v-model:value="values[item]">
|
||||
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
|
||||
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
|
||||
</MkTextarea>
|
||||
<MkSwitch v-else-if="form[item].type === 'boolean'" v-model:value="values[item]">
|
||||
|
||||
@@ -130,10 +130,14 @@ export default defineComponent({
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (style == null) {
|
||||
return h('span', {}, ['[', token.node.props.name, ...genEl(token.children), ']']);
|
||||
} else {
|
||||
return h('span', {
|
||||
style: 'display: inline-block;' + style,
|
||||
}, genEl(token.children));
|
||||
}
|
||||
}
|
||||
|
||||
case 'small': {
|
||||
return [h('small', {
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineAsyncComponent, defineComponent, markRaw, ref } from 'vue';
|
||||
import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||
import { parse } from '../../mfm/parse';
|
||||
import { sum, unique } from '../../prelude/array';
|
||||
@@ -498,9 +498,9 @@ export default defineComponent({
|
||||
react(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
this.blur();
|
||||
if (this.$store.state.device.useFullReactionPicker) {
|
||||
os.popup(import('@/components/emoji-picker.vue'), {
|
||||
src: this.$refs.reactButton,
|
||||
compact: !this.$store.state.device.useFullReactionPicker
|
||||
}, {
|
||||
done: reaction => {
|
||||
if (reaction) {
|
||||
@@ -512,22 +512,6 @@ export default defineComponent({
|
||||
this.focus();
|
||||
},
|
||||
}, 'closed');
|
||||
} else {
|
||||
os.popup(import('@/components/reaction-picker.vue'), {
|
||||
showFocus: viaKeyboard,
|
||||
src: this.$refs.reactButton,
|
||||
}, {
|
||||
done: reaction => {
|
||||
if (reaction) {
|
||||
os.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
});
|
||||
}
|
||||
this.focus();
|
||||
},
|
||||
}, 'closed');
|
||||
}
|
||||
},
|
||||
|
||||
reactDirectly(reaction) {
|
||||
@@ -626,6 +610,11 @@ export default defineComponent({
|
||||
text: this.$t('favorite'),
|
||||
action: () => this.toggleFavorite(true)
|
||||
}),
|
||||
{
|
||||
icon: faPaperclip,
|
||||
text: this.$t('clip'),
|
||||
action: () => this.clip()
|
||||
},
|
||||
(this.appearNote.userId != this.$store.state.i.id) ? statePromise.then(state => state.isWatching ? {
|
||||
icon: faEyeSlash,
|
||||
text: this.$t('unwatch'),
|
||||
@@ -778,6 +767,43 @@ export default defineComponent({
|
||||
});
|
||||
},
|
||||
|
||||
async clip() {
|
||||
const clips = await os.api('clips/list');
|
||||
os.modalMenu([{
|
||||
icon: faPlus,
|
||||
text: this.$t('createNew'),
|
||||
action: async () => {
|
||||
const { canceled, result } = await os.form(this.$t('createNewClip'), {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: this.$t('name')
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
multiline: true,
|
||||
label: this.$t('description')
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
label: this.$t('public')
|
||||
}
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
const clip = await os.apiWithDialog('clips/create', result);
|
||||
|
||||
os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: this.appearNote.id });
|
||||
}
|
||||
}, null, ...clips.map(clip => ({
|
||||
text: clip.name,
|
||||
action: () => {
|
||||
os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: this.appearNote.id });
|
||||
}
|
||||
}))], this.$refs.menuButton, {
|
||||
}).then(this.focus);
|
||||
},
|
||||
|
||||
async promote() {
|
||||
const { canceled, result: days } = await os.dialog({
|
||||
title: this.$t('numberOfDays'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
|
||||
<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj _panel" tabindex="-1">
|
||||
<div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div>
|
||||
<article>
|
||||
<header>
|
||||
@@ -35,16 +35,11 @@ export default defineComponent({
|
||||
<style lang="scss" scoped>
|
||||
.vhpxefrj {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
border: solid var(--lineWidth) var(--urlPreviewBorder);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--divider);
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
border-color: var(--urlPreviewBorderHover);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
> .thumbnail {
|
||||
|
||||
@@ -18,10 +18,11 @@ import XPost from './page.post.vue';
|
||||
import XCounter from './page.counter.vue';
|
||||
import XRadioButton from './page.radio-button.vue';
|
||||
import XCanvas from './page.canvas.vue';
|
||||
import XNote from './page.note.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas
|
||||
XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas, XNote
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
|
||||
39
src/client/components/page/page.note.vue
Normal file
39
src/client/components/page/page.note.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="voxdxuby">
|
||||
<XNote v-if="note" v-model:note="note" :key="note.id" :detail="value.detailed"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import XNote from '@/components/note.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XNote
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
required: true
|
||||
},
|
||||
hpml: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
note: null,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
this.note = await os.api('notes/show', { noteId: this.value.note });
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.voxdxuby {
|
||||
margin: 1em 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,214 +0,0 @@
|
||||
<template>
|
||||
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
|
||||
<div class="rdfaahpb _popup" v-hotkey="keymap">
|
||||
<div class="buttons" ref="buttons" :class="{ showFocus }">
|
||||
<button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :tabindex="i + 1" :title="reaction" v-particle><XReactionIcon :reaction="reaction"/></button>
|
||||
</div>
|
||||
<input class="text" ref="text" v-model.trim="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText">
|
||||
</div>
|
||||
</MkModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { emojiRegex } from '../../misc/emoji-regex';
|
||||
import XReactionIcon from '@/components/reaction-icon.vue';
|
||||
import MkModal from '@/components/ui/modal.vue';
|
||||
import { Autocomplete } from '@/scripts/autocomplete';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XReactionIcon,
|
||||
MkModal,
|
||||
},
|
||||
|
||||
props: {
|
||||
reactions: {
|
||||
required: false
|
||||
},
|
||||
|
||||
showFocus: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
|
||||
src: {
|
||||
required: false
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['done', 'closed'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
rs: this.reactions || this.$store.state.settings.reactions,
|
||||
text: null,
|
||||
focus: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
keymap(): any {
|
||||
return {
|
||||
'esc': this.close,
|
||||
'enter|space|plus': this.choose,
|
||||
'up|k': this.focusUp,
|
||||
'left|h|shift+tab': this.focusLeft,
|
||||
'right|l|tab': this.focusRight,
|
||||
'down|j': this.focusDown,
|
||||
'1': () => this.react(this.rs[0]),
|
||||
'2': () => this.react(this.rs[1]),
|
||||
'3': () => this.react(this.rs[2]),
|
||||
'4': () => this.react(this.rs[3]),
|
||||
'5': () => this.react(this.rs[4]),
|
||||
'6': () => this.react(this.rs[5]),
|
||||
'7': () => this.react(this.rs[6]),
|
||||
'8': () => this.react(this.rs[7]),
|
||||
'9': () => this.react(this.rs[8]),
|
||||
'0': () => this.react(this.rs[9]),
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
focus(i) {
|
||||
this.$refs.buttons.children[i].focus({
|
||||
preventScroll: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.focus = 0;
|
||||
});
|
||||
|
||||
// TODO: detach when unmount
|
||||
new Autocomplete(this.$refs.text, this, { model: 'text' });
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit('done');
|
||||
this.$refs.modal.close();
|
||||
},
|
||||
|
||||
react(reaction) {
|
||||
this.$emit('done', reaction);
|
||||
this.$refs.modal.close();
|
||||
},
|
||||
|
||||
reactText() {
|
||||
if (!this.text) return;
|
||||
this.react(this.text);
|
||||
},
|
||||
|
||||
tryReactText() {
|
||||
if (!this.text) return;
|
||||
if (!this.text.match(emojiRegex)) return;
|
||||
this.reactText();
|
||||
},
|
||||
|
||||
focusUp() {
|
||||
this.focus = this.focus == 0 ? 9 : this.focus < 5 ? (this.focus + 4) : (this.focus - 5);
|
||||
},
|
||||
|
||||
focusDown() {
|
||||
this.focus = this.focus == 9 ? 0 : this.focus >= 5 ? (this.focus - 4) : (this.focus + 5);
|
||||
},
|
||||
|
||||
focusRight() {
|
||||
this.focus = this.focus == 9 ? 0 : (this.focus + 1);
|
||||
},
|
||||
|
||||
focusLeft() {
|
||||
this.focus = this.focus == 0 ? 9 : (this.focus - 1);
|
||||
},
|
||||
|
||||
choose() {
|
||||
this.$refs.buttons.children[this.focus].click();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rdfaahpb {
|
||||
> .buttons {
|
||||
padding: 6px 6px 0 6px;
|
||||
width: 212px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
|
||||
@media (max-width: 1025px) {
|
||||
padding: 8px 8px 0 8px;
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
&.showFocus {
|
||||
> button:focus {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border: 2px solid var(--focus);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
padding: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 24px;
|
||||
border-radius: 2px;
|
||||
|
||||
@media (max-width: 1025px) {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
> * {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--accent);
|
||||
box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .text {
|
||||
width: 208px;
|
||||
padding: 8px;
|
||||
margin: 0 0 6px 0;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
outline: none;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
|
||||
@media (max-width: 1025px) {
|
||||
width: 256px;
|
||||
margin: 4px 0 8px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -51,7 +50,7 @@ export default defineComponent({
|
||||
.novjtctn {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 16px 32px 0 0;
|
||||
margin: 8px 20px 0 0;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
58
src/client/components/ui/radios.vue
Normal file
58
src/client/components/ui/radios.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, h } from 'vue';
|
||||
import MkRadio from '@/components/ui/radio.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkRadio
|
||||
},
|
||||
props: {
|
||||
defs: {
|
||||
required: true
|
||||
},
|
||||
modelValue: {
|
||||
required: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: this.modelValue,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.$emit('update:modelValue', this.value);
|
||||
}
|
||||
},
|
||||
render() {
|
||||
const label = this.$slots.desc();
|
||||
const options = this.$slots.default();
|
||||
|
||||
return h('div', {
|
||||
class: 'novjtcto'
|
||||
}, [
|
||||
h('div', label),
|
||||
...options.map(option => h(MkRadio, {
|
||||
key: option.props.value,
|
||||
value: option.props.value,
|
||||
modelValue: this.value,
|
||||
'onUpdate:modelValue': value => this.value = value,
|
||||
}, option.children))
|
||||
]);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.novjtcto {
|
||||
margin: 32px 0;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -275,10 +275,11 @@ export async function selectDriveFolder(multiple: boolean) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function pickEmoji(src?: HTMLElement) {
|
||||
export async function pickEmoji(src?: HTMLElement, opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
popup(import('@/components/emoji-picker.vue'), {
|
||||
src
|
||||
src,
|
||||
...opts
|
||||
}, {
|
||||
done: emoji => {
|
||||
resolve(emoji);
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<section class="_section">
|
||||
<div class="_content">
|
||||
<div class="_card">
|
||||
<div class="_title"><Mfm text="<motion>❤</motion>"/> {{ $t('patrons') }}</div>
|
||||
<div class="_title"><Mfm text="[jelly ❤]"/> {{ $t('patrons') }}</div>
|
||||
<div class="_content">
|
||||
<ul style="margin: 0;">
|
||||
<li>Gargron</li>
|
||||
|
||||
154
src/client/pages/clip.vue
Normal file
154
src/client/pages/clip.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div v-if="clip" class="_section">
|
||||
<div class="okzinsic _content _panel _vMargin">
|
||||
<div class="description" v-if="clip.description">
|
||||
<Mfm :text="clip.description" :is-note="false" :i="$store.state.i"/>
|
||||
</div>
|
||||
<div class="user">
|
||||
<MkAvatar :user="clip.user" class="avatar"/> <MkUserName :user="clip.user" :nowrap="false"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<XNotes class="_content _vMargin" :pagination="pagination" :detail="true"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { faEllipsisH, faPaperclip, faPencilAlt, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import MkContainer from '@/components/ui/container.vue';
|
||||
import XPostForm from '@/components/post-form.vue';
|
||||
import XNotes from '@/components/notes.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkContainer,
|
||||
XPostForm,
|
||||
XNotes,
|
||||
},
|
||||
|
||||
props: {
|
||||
clipId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
INFO: computed(() => this.clip ? {
|
||||
title: this.clip.name,
|
||||
icon: faPaperclip,
|
||||
action: {
|
||||
icon: faEllipsisH,
|
||||
handler: this.menu
|
||||
}
|
||||
} : null),
|
||||
clip: null,
|
||||
pagination: {
|
||||
endpoint: 'clips/notes',
|
||||
limit: 10,
|
||||
params: () => ({
|
||||
clipId: this.clipId,
|
||||
})
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isOwned(): boolean {
|
||||
return this.$store.getters.isSignedIn && this.clip && (this.$store.state.i.id === this.clip.userId);
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
clipId: {
|
||||
async handler() {
|
||||
this.clip = await os.api('clips/show', {
|
||||
clipId: this.clipId,
|
||||
});
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
menu(ev) {
|
||||
os.modalMenu([this.isOwned ? {
|
||||
icon: faPencilAlt,
|
||||
text: this.$t('edit'),
|
||||
action: async () => {
|
||||
const { canceled, result } = await os.form(this.clip.name, {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: this.$t('name'),
|
||||
default: this.clip.name
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
multiline: true,
|
||||
label: this.$t('description'),
|
||||
default: this.clip.description
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
label: this.$t('public'),
|
||||
default: this.clip.isPublic
|
||||
}
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog('clips/update', {
|
||||
clipId: this.clip.id,
|
||||
...result
|
||||
});
|
||||
}
|
||||
} : undefined, this.isOwned ? {
|
||||
icon: faTrashAlt,
|
||||
text: this.$t('delete'),
|
||||
danger: true,
|
||||
action: async () => {
|
||||
const { canceled } = await os.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('deleteAreYouSure', { x: this.clip.name }),
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('clips/delete', {
|
||||
clipId: this.clip.id,
|
||||
});
|
||||
}
|
||||
} : undefined], ev.currentTarget || ev.target);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.okzinsic {
|
||||
position: relative;
|
||||
|
||||
> .description {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
> .user {
|
||||
$height: 32px;
|
||||
padding: 16px;
|
||||
border-top: solid 1px var(--divider);
|
||||
line-height: $height;
|
||||
|
||||
> .avatar {
|
||||
width: $height;
|
||||
height: $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -6,7 +6,7 @@
|
||||
<XAntenna v-if="draft" :antenna="draft" @created="onAntennaCreated" style="margin-bottom: var(--margin);"/>
|
||||
|
||||
<MkPagination :pagination="pagination" #default="{items}" class="antennas" ref="list">
|
||||
<XAntenna v-for="(antenna, i) in items" :key="antenna.id" :antenna="antenna" @created="onAntennaDeleted"/>
|
||||
<XAntenna v-for="(antenna, i) in items" :key="antenna.id" :antenna="antenna" @deleted="onAntennaDeleted"/>
|
||||
</MkPagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
104
src/client/pages/my-clips/index.vue
Normal file
104
src/client/pages/my-clips/index.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="_section qtcaoidl">
|
||||
<MkButton @click="create" primary class="add"><Fa :icon="faPlus"/> {{ $t('add') }}</MkButton>
|
||||
|
||||
<div class="_content">
|
||||
<MkPagination :pagination="pagination" #default="{items}" ref="list" class="list">
|
||||
<MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _vMargin">
|
||||
<b>{{ item.name }}</b>
|
||||
<div v-if="item.description" class="description">{{ item.description }}</div>
|
||||
</MkA>
|
||||
</MkPagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { faPlus, faPaperclip } from '@fortawesome/free-solid-svg-icons';
|
||||
import MkPagination from '@/components/ui/pagination.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkPagination,
|
||||
MkButton,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
INFO: {
|
||||
title: this.$t('clip'),
|
||||
icon: faPaperclip,
|
||||
action: {
|
||||
icon: faPlus,
|
||||
handler: this.create
|
||||
}
|
||||
},
|
||||
pagination: {
|
||||
endpoint: 'clips/list',
|
||||
limit: 10,
|
||||
},
|
||||
draft: null,
|
||||
faPlus
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
async create() {
|
||||
const { canceled, result } = await os.form(this.$t('createNewClip'), {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: this.$t('name')
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
multiline: true,
|
||||
label: this.$t('description')
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
label: this.$t('public')
|
||||
}
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog('clips/create', result);
|
||||
},
|
||||
|
||||
onClipCreated() {
|
||||
this.$refs.list.reload();
|
||||
this.draft = null;
|
||||
},
|
||||
|
||||
onClipDeleted() {
|
||||
this.$refs.list.reload();
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.qtcaoidl {
|
||||
> .add {
|
||||
margin: 0 auto 16px auto;
|
||||
}
|
||||
|
||||
> ._content {
|
||||
> .list {
|
||||
> .item {
|
||||
display: block;
|
||||
padding: 16px;
|
||||
|
||||
> .description {
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: solid 1px var(--divider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
65
src/client/pages/page-editor/els/page-editor.el.note.vue
Normal file
65
src/client/pages/page-editor/els/page-editor.el.note.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<XContainer @remove="() => $emit('remove')" :draggable="true">
|
||||
<template #header><Fa :icon="faStickyNote"/> {{ $t('_pages.blocks.note') }}</template>
|
||||
|
||||
<section style="padding: 0 16px 0 16px;">
|
||||
<MkInput v-model:value="id">
|
||||
<span>{{ $t('_pages.blocks._note.id') }}</span>
|
||||
<template #desc>{{ $t('_pages.blocks._note.idDescription') }}</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model:value="value.detailed"><span>{{ $t('_pages.blocks._note.detailed') }}</span></MkSwitch>
|
||||
|
||||
<XNote v-if="note" v-model:note="note" :key="note.id + ':' + (value.detailed ? 'detailed' : 'normal')" :detail="value.detailed" style="margin-bottom: 16px;"/>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { faStickyNote } from '@fortawesome/free-solid-svg-icons';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/ui/input.vue';
|
||||
import MkSwitch from '@/components/ui/switch.vue';
|
||||
import XNote from '@/components/note.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XContainer, MkInput, MkSwitch, XNote
|
||||
},
|
||||
|
||||
props: {
|
||||
value: {
|
||||
required: true
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
id: this.value.note,
|
||||
note: null,
|
||||
faStickyNote
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
id: {
|
||||
async handler() {
|
||||
if (this.id && (this.id.startsWith('http://') || this.id.startsWith('https://'))) {
|
||||
this.value.note = this.id.endsWith('/') ? this.id.substr(0, this.id.length - 1).split('/').pop() : this.id.split('/').pop();
|
||||
} else {
|
||||
this.value.note = this.id;
|
||||
}
|
||||
|
||||
this.note = await os.api('notes/show', { noteId: this.value.note });
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.value.note == null) this.value.note = null;
|
||||
if (this.value.detailed == null) this.value.detailed = false;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -20,12 +20,13 @@ import XPost from './els/page-editor.el.post.vue';
|
||||
import XCounter from './els/page-editor.el.counter.vue';
|
||||
import XRadioButton from './els/page-editor.el.radio-button.vue';
|
||||
import XCanvas from './els/page-editor.el.canvas.vue';
|
||||
import XNote from './els/page-editor.el.note.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XDraggable: defineAsyncComponent(() => import('vue-draggable-next').then(x => x.VueDraggableNext)),
|
||||
XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas
|
||||
XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas, XNote
|
||||
},
|
||||
|
||||
props: {
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
<template>
|
||||
<div class="_section">
|
||||
<div class="_content">
|
||||
<div class="gwbmwxkm _panel _vMargin">
|
||||
<header>
|
||||
<div class="title"><Fa :icon="faStickyNote"/> {{ readonly ? $t('_pages.readPage') : pageId ? $t('_pages.editPage') : $t('_pages.newPage') }}</div>
|
||||
<div class="buttons">
|
||||
<button class="_button" @click="del()" v-if="!readonly"><Fa :icon="faTrashAlt"/></button>
|
||||
<button class="_button" @click="() => showOptions = !showOptions"><Fa :icon="faCog"/></button>
|
||||
<button class="_button" @click="save()" v-if="!readonly"><Fa :icon="faSave"/></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section>
|
||||
<MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $t('_pages.viewPage') }}</MkA>
|
||||
|
||||
<MkButton @click="save" primary class="save" style="margin: 16px auto 16px auto;"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
||||
|
||||
<MkContainer :body-togglable="true" :expanded="true" class="_vMargin">
|
||||
<template #header><Fa :icon="faCog"/> {{ $t('_pages.pageSetting') }}</template>
|
||||
<div class="_section">
|
||||
<MkInput v-model:value="title">
|
||||
<span>{{ $t('_pages.title') }}</span>
|
||||
</MkInput>
|
||||
|
||||
<template v-if="showOptions">
|
||||
<MkInput v-model:value="summary">
|
||||
<span>{{ $t('_pages.summary') }}</span>
|
||||
</MkInput>
|
||||
@@ -39,19 +32,23 @@
|
||||
<MkSwitch v-model:value="hideTitleWhenPinned">{{ $t('_pages.hideTitleWhenPinned') }}</MkSwitch>
|
||||
|
||||
<div class="eyeCatch">
|
||||
<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><Fa :icon="faPlus"/> {{ $t('_pages.eyeCatchingImageSet') }}</MkButton>
|
||||
<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><Fa :icon="faPlus"/> {{ $t('_pages.eyeCatchingImageSet') }}</MkButton>
|
||||
<div v-else-if="eyeCatchingImage">
|
||||
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/>
|
||||
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
|
||||
<MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><Fa :icon="faTrashAlt"/> {{ $t('_pages.eyeCatchingImageRemove') }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</MkContainer>
|
||||
|
||||
<MkContainer :body-togglable="true" :expanded="true" class="_vMargin">
|
||||
<template #header><Fa :icon="faStickyNote"/> {{ $t('_pages.contents') }}</template>
|
||||
<div class="_section">
|
||||
<XBlocks class="content" v-model:value="content" :hpml="hpml"/>
|
||||
|
||||
<MkButton @click="add()" v-if="!readonly"><Fa :icon="faPlus"/></MkButton>
|
||||
</section>
|
||||
</div>
|
||||
</MkContainer>
|
||||
|
||||
<MkContainer :body-togglable="true" class="_vMargin">
|
||||
<template #header><Fa :icon="faMagic"/> {{ $t('_pages.variables') }}</template>
|
||||
@@ -85,14 +82,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent } from 'vue';
|
||||
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
||||
import 'prismjs';
|
||||
import { highlight, languages } from 'prismjs/components/prism-core';
|
||||
import 'prismjs/components/prism-clike';
|
||||
import 'prismjs/components/prism-javascript';
|
||||
import 'prismjs/themes/prism-okaidia.css';
|
||||
import 'vue-prism-editor/dist/prismeditor.min.css';
|
||||
import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XVariable from './page-editor.script-block.vue';
|
||||
@@ -108,6 +105,7 @@ import { HpmlTypeChecker } from '@/scripts/hpml/type-checker';
|
||||
import { url } from '@/config';
|
||||
import { collectPageVars } from '@/scripts/collect-page-vars';
|
||||
import * as os from '@/os';
|
||||
import { selectFile } from '@/scripts/select-file';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -132,6 +130,13 @@ export default defineComponent({
|
||||
|
||||
data() {
|
||||
return {
|
||||
INFO: computed(() => this.initPageId ? {
|
||||
title: this.$t('_pages.editPage'),
|
||||
icon: faPencilAlt,
|
||||
} : {
|
||||
title: this.$t('_pages.newPage'),
|
||||
icon: faPencilAlt,
|
||||
}),
|
||||
author: this.$store.state.i,
|
||||
readonly: false,
|
||||
page: null,
|
||||
@@ -149,7 +154,6 @@ export default defineComponent({
|
||||
variables: [],
|
||||
hpml: null,
|
||||
script: '',
|
||||
showOptions: false,
|
||||
url,
|
||||
faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode
|
||||
};
|
||||
@@ -353,6 +357,7 @@ export default defineComponent({
|
||||
{ value: 'text', text: this.$t('_pages.blocks.text') },
|
||||
{ value: 'image', text: this.$t('_pages.blocks.image') },
|
||||
{ value: 'textarea', text: this.$t('_pages.blocks.textarea') },
|
||||
{ value: 'note', text: this.$t('_pages.blocks.note') },
|
||||
{ value: 'canvas', text: this.$t('_pages.blocks.canvas') },
|
||||
]
|
||||
}, {
|
||||
@@ -413,8 +418,8 @@ export default defineComponent({
|
||||
return list;
|
||||
},
|
||||
|
||||
setEyeCatchingImage() {
|
||||
os.selectDriveFile(false).then(file => {
|
||||
setEyeCatchingImage(e) {
|
||||
selectFile(e.currentTarget || e.target, null, false).then(file => {
|
||||
this.eyeCatchingImageId = file.id;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,38 +1,40 @@
|
||||
<template>
|
||||
<div class="_section">
|
||||
<div class="">
|
||||
<section class="_card _vMargin">
|
||||
<div class="_title"><Fa :icon="faCog"/> {{ $t('general') }}</div>
|
||||
<div class="_content">
|
||||
<div>{{ $t('defaultNavigationBehaviour') }}</div>
|
||||
<MkSwitch v-model:value="defaultSideView">{{ $t('openInSideView') }}</MkSwitch>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<div>{{ $t('whenServerDisconnected') }}</div>
|
||||
<MkRadio v-model="serverDisconnectedBehavior" value="reload">{{ $t('_serverDisconnectedBehavior.reload') }}</MkRadio>
|
||||
<MkRadio v-model="serverDisconnectedBehavior" value="dialog">{{ $t('_serverDisconnectedBehavior.dialog') }}</MkRadio>
|
||||
<MkRadio v-model="serverDisconnectedBehavior" value="quiet">{{ $t('_serverDisconnectedBehavior.quiet') }}</MkRadio>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<MkRadios v-model="serverDisconnectedBehavior">
|
||||
<template #desc>{{ $t('whenServerDisconnected') }}</template>
|
||||
<option value="reload">{{ $t('_serverDisconnectedBehavior.reload') }}</option>
|
||||
<option value="dialog">{{ $t('_serverDisconnectedBehavior.dialog') }}</option>
|
||||
<option value="quiet">{{ $t('_serverDisconnectedBehavior.quiet') }}</option>
|
||||
</MkRadios>
|
||||
<MkSwitch v-model:value="imageNewTab">{{ $t('openImageInNewTab') }}</MkSwitch>
|
||||
<MkSwitch v-model:value="showFixedPostForm">{{ $t('showFixedPostForm') }}</MkSwitch>
|
||||
<MkSwitch v-model:value="enableInfiniteScroll">{{ $t('enableInfiniteScroll') }}</MkSwitch>
|
||||
<MkSwitch v-model:value="disablePagesScript">{{ $t('disablePagesScript') }}</MkSwitch>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<div>{{ $t('chatOpenBehavior') }}</div>
|
||||
<MkRadio v-model="chatOpenBehavior" value="page">{{ $t('showInPage') }}</MkRadio>
|
||||
<MkRadio v-model="chatOpenBehavior" value="window">{{ $t('openInWindow') }}</MkRadio>
|
||||
<MkRadio v-model="chatOpenBehavior" value="popout">{{ $t('popout') }}</MkRadio>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<MkSelect v-model:value="lang">
|
||||
<template #label>{{ $t('uiLanguage') }}</template>
|
||||
|
||||
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
|
||||
</MkSelect>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="_card _vMargin">
|
||||
<div class="_title"><Fa :icon="faCog"/> {{ $t('defaultNavigationBehaviour') }}</div>
|
||||
<div class="_content">
|
||||
<MkSwitch v-model:value="defaultSideView">{{ $t('openInSideView') }}</MkSwitch>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<MkRadios v-model="chatOpenBehavior">
|
||||
<template #desc>{{ $t('chatOpenBehavior') }}</template>
|
||||
<option value="page">{{ $t('showInPage') }}</option>
|
||||
<option value="window">{{ $t('openInWindow') }}</option>
|
||||
<option value="popout">{{ $t('popout') }}</option>
|
||||
</MkRadios>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="_card _vMargin">
|
||||
<div class="_title"><Fa :icon="faCog"/> {{ $t('appearance') }}</div>
|
||||
<div class="_content">
|
||||
@@ -43,19 +45,19 @@
|
||||
{{ $t('useOsNativeEmojis') }}
|
||||
<template #desc><Mfm text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<div>{{ $t('fontSize') }}</div>
|
||||
<MkRadio v-model="fontSize" value="small"><span style="font-size: 14px;">Aa</span></MkRadio>
|
||||
<MkRadio v-model="fontSize" :value="null"><span style="font-size: 16px;">Aa</span></MkRadio>
|
||||
<MkRadio v-model="fontSize" value="large"><span style="font-size: 18px;">Aa</span></MkRadio>
|
||||
<MkRadio v-model="fontSize" value="veryLarge"><span style="font-size: 20px;">Aa</span></MkRadio>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<div>{{ $t('instanceTicker') }}</div>
|
||||
<MkRadio v-model="instanceTicker" value="none">{{ $t('_instanceTicker.none') }}</MkRadio>
|
||||
<MkRadio v-model="instanceTicker" value="remote">{{ $t('_instanceTicker.remote') }}</MkRadio>
|
||||
<MkRadio v-model="instanceTicker" value="always">{{ $t('_instanceTicker.always') }}</MkRadio>
|
||||
<MkRadios v-model="fontSize">
|
||||
<template #desc>{{ $t('fontSize') }}</template>
|
||||
<option value="small"><span style="font-size: 14px;">Aa</span></option>
|
||||
<option :value="null"><span style="font-size: 16px;">Aa</span></option>
|
||||
<option value="large"><span style="font-size: 18px;">Aa</span></option>
|
||||
<option value="veryLarge"><span style="font-size: 20px;">Aa</span></option>
|
||||
</MkRadios>
|
||||
<MkRadios v-model="instanceTicker">
|
||||
<template #desc>{{ $t('instanceTicker') }}</template>
|
||||
<option value="none">{{ $t('_instanceTicker.none') }}</option>
|
||||
<option value="remote">{{ $t('_instanceTicker.remote') }}</option>
|
||||
<option value="always">{{ $t('_instanceTicker.always') }}</option>
|
||||
</MkRadios>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -88,6 +90,7 @@ import MkButton from '@/components/ui/button.vue';
|
||||
import MkSwitch from '@/components/ui/switch.vue';
|
||||
import MkSelect from '@/components/ui/select.vue';
|
||||
import MkRadio from '@/components/ui/radio.vue';
|
||||
import MkRadios from '@/components/ui/radios.vue';
|
||||
import MkRange from '@/components/ui/range.vue';
|
||||
import { langs } from '@/config';
|
||||
import { clientDb, set } from '@/db';
|
||||
@@ -99,6 +102,7 @@ export default defineComponent({
|
||||
MkSwitch,
|
||||
MkSelect,
|
||||
MkRadio,
|
||||
MkRadios,
|
||||
MkRange,
|
||||
},
|
||||
|
||||
|
||||
@@ -31,9 +31,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="main">
|
||||
<transition :name="($store.state.device.animation && !narrow) ? 'view-slide' : ''" appear mode="out-in">
|
||||
<component :is="component" @info="onInfo"/>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -109,14 +107,6 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.view-slide-enter-active, .view-slide-leave-active {
|
||||
transition: opacity 0.3s, transform 0.3s !important;
|
||||
}
|
||||
.view-slide-enter-from, .view-slide-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(32px);
|
||||
}
|
||||
|
||||
.vvcocwet {
|
||||
> .nav {
|
||||
> .menu {
|
||||
@@ -133,7 +123,7 @@ export default defineComponent({
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0 32px;
|
||||
line-height: 48px;
|
||||
line-height: 40px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -168,10 +158,22 @@ export default defineComponent({
|
||||
> .nav {
|
||||
width: 30%;
|
||||
max-width: 300px;
|
||||
font-size: 0.95em;
|
||||
border-right: solid 1px var(--divider);
|
||||
}
|
||||
|
||||
> .main {
|
||||
flex: 1;
|
||||
padding: 32px;
|
||||
--baseContentWidth: 100%;
|
||||
|
||||
::v-deep(._section) {
|
||||
padding: 0 0 32px 0;
|
||||
|
||||
& + ._section {
|
||||
padding-top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,21 @@
|
||||
<div class="_card">
|
||||
<div class="_title"><Fa :icon="faLaugh"/> {{ $t('reaction') }}</div>
|
||||
<div class="_content">
|
||||
<MkInput v-model:value="reactions" style="font-family: 'Segoe UI Emoji', 'Noto Color Emoji', Roboto, HelveticaNeue, Arial, sans-serif">
|
||||
{{ $t('reaction') }}<template #desc>{{ $t('reactionSettingDescription') }} <button class="_textButton" @click="chooseEmoji">{{ $t('chooseEmoji') }}</button></template>
|
||||
</MkInput>
|
||||
<MkButton inline @click="setDefault"><Fa :icon="faUndo"/> {{ $t('default') }}</MkButton>
|
||||
<div class="_caption" style="padding: 0 8px 8px 8px;">{{ $t('reactionSettingDescription') }}</div>
|
||||
<XDraggable class="zoaiodol" :list="reactions" animation="150" delay="100" delay-on-touch-only="true">
|
||||
<button class="_button item" v-for="reaction in reactions" :key="reaction" @click="remove(reaction, $event)">
|
||||
<MkEmoji :emoji="reaction" :normal="true"/>
|
||||
</button>
|
||||
<template #footer>
|
||||
<button>a</button>
|
||||
</template>
|
||||
</XDraggable>
|
||||
<div class="_caption" style="padding: 8px;">{{ $t('reactionSettingDescription2') }} <button class="_textButton" @click="chooseEmoji">{{ $t('chooseEmoji') }}</button></div>
|
||||
<MkSwitch v-model:value="useFullReactionPicker">{{ $t('useFullReactionPicker') }}</MkSwitch>
|
||||
</div>
|
||||
<div class="_footer">
|
||||
<MkButton @click="save()" primary inline :disabled="!changed"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
||||
<MkButton inline @click="preview"><Fa :icon="faEye"/> {{ $t('preview') }}</MkButton>
|
||||
<MkButton inline @click="setDefault"><Fa :icon="faUndo"/> {{ $t('default') }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,6 +27,7 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { faLaugh, faSave, faEye } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faUndo } from '@fortawesome/free-solid-svg-icons';
|
||||
import { VueDraggableNext } from 'vue-draggable-next';
|
||||
import MkInput from '@/components/ui/input.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import MkSwitch from '@/components/ui/switch.vue';
|
||||
@@ -33,6 +40,7 @@ export default defineComponent({
|
||||
MkInput,
|
||||
MkButton,
|
||||
MkSwitch,
|
||||
XDraggable: VueDraggableNext,
|
||||
},
|
||||
|
||||
emits: ['info'],
|
||||
@@ -43,17 +51,12 @@ export default defineComponent({
|
||||
title: this.$t('reaction'),
|
||||
icon: faLaugh
|
||||
},
|
||||
reactions: this.$store.state.settings.reactions.join(''),
|
||||
changed: false,
|
||||
reactions: JSON.parse(JSON.stringify(this.$store.state.settings.reactions)),
|
||||
faLaugh, faSave, faEye, faUndo
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
splited(): any {
|
||||
return this.reactions.match(emojiRegexWithCustom);
|
||||
},
|
||||
|
||||
useFullReactionPicker: {
|
||||
get() { return this.$store.state.device.useFullReactionPicker; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'useFullReactionPicker', value: value }); }
|
||||
@@ -63,7 +66,7 @@ export default defineComponent({
|
||||
watch: {
|
||||
reactions: {
|
||||
handler() {
|
||||
this.changed = true;
|
||||
this.save();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
@@ -75,34 +78,59 @@ export default defineComponent({
|
||||
|
||||
methods: {
|
||||
save() {
|
||||
this.$store.dispatch('settings/set', { key: 'reactions', value: this.splited });
|
||||
this.changed = false;
|
||||
this.$store.dispatch('settings/set', { key: 'reactions', value: this.reactions });
|
||||
},
|
||||
|
||||
remove(reaction, ev) {
|
||||
os.modalMenu([{
|
||||
text: this.$t('remove'),
|
||||
action: () => {
|
||||
this.reactions = this.reactions.filter(x => x !== reaction)
|
||||
}
|
||||
}], ev.currentTarget || ev.target);
|
||||
},
|
||||
|
||||
preview(ev) {
|
||||
if (this.$store.state.device.useFullReactionPicker) {
|
||||
os.popup(import('@/components/emoji-picker.vue'), {
|
||||
overridePinned: this.splited,
|
||||
compact: !this.$store.state.device.useFullReactionPicker,
|
||||
src: ev.currentTarget || ev.target,
|
||||
}, {}, 'closed');
|
||||
} else {
|
||||
os.popup(import('@/components/reaction-picker.vue'), {
|
||||
reactions: this.splited,
|
||||
showFocus: false,
|
||||
src: ev.currentTarget || ev.target,
|
||||
}, {}, 'closed');
|
||||
}
|
||||
},
|
||||
|
||||
setDefault() {
|
||||
this.reactions = defaultSettings.reactions.join('');
|
||||
async setDefault() {
|
||||
const { canceled } = await os.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('resetAreYouSure'),
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
this.reactions = JSON.parse(JSON.stringify(defaultSettings.reactions));
|
||||
},
|
||||
|
||||
chooseEmoji(ev) {
|
||||
os.pickEmoji(ev.currentTarget || ev.target).then(emoji => {
|
||||
this.reactions += emoji;
|
||||
os.pickEmoji(ev.currentTarget || ev.target, {
|
||||
showPinned: false
|
||||
}).then(emoji => {
|
||||
if (!this.reactions.includes(emoji)) {
|
||||
this.reactions.push(emoji);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.zoaiodol {
|
||||
border: solid 1px var(--divider);
|
||||
border-radius: var(--radius);
|
||||
padding: 16px;
|
||||
|
||||
> .item {
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="_section">
|
||||
<div class="">
|
||||
<div class="rfqxtzch _card _vMargin">
|
||||
<div class="_content">
|
||||
<div class="darkMode" :class="{ disabled: syncDeviceDarkMode }">
|
||||
@@ -22,8 +22,12 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<MkSwitch v-model:value="syncDeviceDarkMode">{{ $t('syncDeviceDarkMode') }}</MkSwitch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="_card _vMargin">
|
||||
<div class="_content">
|
||||
<MkSelect v-model:value="lightTheme">
|
||||
<template #label>{{ $t('themeForLightMode') }}</template>
|
||||
|
||||
@@ -162,7 +162,7 @@ export default defineComponent({
|
||||
dialogCancelByBgClick: true,
|
||||
dialogInput: false,
|
||||
dialogResult: null,
|
||||
formTitle: null,
|
||||
formTitle: 'Test form',
|
||||
formForm: JSON.stringify({
|
||||
foo: {
|
||||
type: 'boolean',
|
||||
@@ -179,6 +179,12 @@ export default defineComponent({
|
||||
default: 'Misskey makes you happy.',
|
||||
label: 'This is a string property'
|
||||
},
|
||||
qux: {
|
||||
type: 'string',
|
||||
multiline: true,
|
||||
default: 'Misskey makes\nyou happy.',
|
||||
label: 'Multiline string'
|
||||
},
|
||||
}, null, '\t'),
|
||||
formResult: null,
|
||||
mfm: '',
|
||||
|
||||
@@ -37,6 +37,7 @@ export const router = createRouter({
|
||||
{ path: '/channels/new', component: page('channel-editor') },
|
||||
{ path: '/channels/:channelId/edit', component: page('channel-editor'), props: true },
|
||||
{ path: '/channels/:channelId', component: page('channel'), props: route => ({ channelId: route.params.channelId }) },
|
||||
{ path: '/clips/:clipId', component: page('clip'), props: route => ({ clipId: route.params.clipId }) },
|
||||
{ path: '/my/notifications', component: page('notifications') },
|
||||
{ path: '/my/favorites', component: page('favorites') },
|
||||
{ path: '/my/messages', component: page('messages') },
|
||||
@@ -55,6 +56,7 @@ export const router = createRouter({
|
||||
{ path: '/my/groups', component: page('my-groups/index') },
|
||||
{ path: '/my/groups/:group', component: page('my-groups/group') },
|
||||
{ path: '/my/antennas', component: page('my-antennas/index') },
|
||||
{ path: '/my/clips', component: page('my-clips/index') },
|
||||
{ path: '/my/apps', component: page('apps') },
|
||||
{ path: '/scratchpad', component: page('scratchpad') },
|
||||
{ path: '/instance', component: page('instance/index') },
|
||||
@@ -73,6 +75,7 @@ export const router = createRouter({
|
||||
{ path: '/games/reversi', component: page('reversi/index') },
|
||||
{ path: '/games/reversi/:gameId', component: page('reversi/game'), props: route => ({ gameId: route.params.gameId }) },
|
||||
{ path: '/mfm-cheat-sheet', component: page('mfm-cheat-sheet') },
|
||||
{ path: '/api-console', component: page('api-console') },
|
||||
{ path: '/test', component: page('test') },
|
||||
{ path: '/auth/:token', component: page('auth') },
|
||||
{ path: '/miauth/:session', component: page('miauth') },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { faBell, faComments, faEnvelope } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faAt, faBroadcastTower, faCloud, faColumns, faDoorClosed, faFileAlt, faFireAlt, faGamepad, faHashtag, faListUl, faSatellite, faSatelliteDish, faSearch, faStar, faTerminal, faUserClock, faUsers } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faAt, faBroadcastTower, faCloud, faColumns, faDoorClosed, faFileAlt, faFireAlt, faGamepad, faHashtag, faListUl, faPaperclip, faSatellite, faSatelliteDish, faSearch, faStar, faTerminal, faUserClock, faUsers } from '@fortawesome/free-solid-svg-icons';
|
||||
import { computed } from 'vue';
|
||||
import { store } from '@/store';
|
||||
import { search } from '@/scripts/search';
|
||||
@@ -99,6 +99,12 @@ export const sidebarDef = {
|
||||
show: computed(() => store.getters.isSignedIn),
|
||||
to: '/my/pages',
|
||||
},
|
||||
clips: {
|
||||
title: 'clip',
|
||||
icon: faPaperclip,
|
||||
show: computed(() => store.getters.isSignedIn),
|
||||
to: '/my/clips',
|
||||
},
|
||||
channels: {
|
||||
title: 'channel',
|
||||
icon: faSatelliteDish,
|
||||
|
||||
@@ -253,7 +253,7 @@ export const store = createStore({
|
||||
|
||||
init(state, x) {
|
||||
for (const [key, value] of Object.entries(defaultDeviceUserSettings)) {
|
||||
if (x[key]) {
|
||||
if (Object.prototype.hasOwnProperty.call(x, key)) {
|
||||
state[key] = x[key];
|
||||
} else {
|
||||
state[key] = value;
|
||||
@@ -471,7 +471,7 @@ export const store = createStore({
|
||||
|
||||
init(state, x) {
|
||||
for (const [key, value] of Object.entries(defaultSettings)) {
|
||||
if (x[key]) {
|
||||
if (Object.prototype.hasOwnProperty.call(x, key)) {
|
||||
state[key] = x[key];
|
||||
} else {
|
||||
state[key] = value;
|
||||
|
||||
@@ -244,7 +244,7 @@ hr {
|
||||
> ._title {
|
||||
margin: 0;
|
||||
padding: 22px 32px;
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
border-bottom: solid 1px var(--panelHeaderDivider);
|
||||
font-weight: bold;
|
||||
background: var(--panelHeaderBg);
|
||||
|
||||
@@ -6,7 +6,7 @@ Misskey Webクライアントのプラグイン機能を使うと、クライア
|
||||
プラグインは、AiScriptのメタデータ埋め込み機能を使って、デフォルトとしてプラグインのメタデータを定義する必要があります。
|
||||
メタデータは次のプロパティを含むオブジェクトです。
|
||||
|
||||
### mame
|
||||
### name
|
||||
プラグイン名
|
||||
|
||||
### author
|
||||
|
||||
@@ -52,7 +52,7 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione
|
||||
blockCode(token) {
|
||||
const pre = doc.createElement('pre');
|
||||
const inner = doc.createElement('code');
|
||||
inner.innerHTML = token.node.props.code;
|
||||
inner.textContent = token.node.props.code;
|
||||
pre.appendChild(inner);
|
||||
return pre;
|
||||
},
|
||||
|
||||
@@ -35,4 +35,10 @@ export class Clip {
|
||||
default: false
|
||||
})
|
||||
public isPublic: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 2048, nullable: true, default: null,
|
||||
comment: 'The description of the Clip.'
|
||||
})
|
||||
public description: string | null;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { EntityRepository, Repository } from 'typeorm';
|
||||
import { Clip } from '../entities/clip';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import { SchemaType } from '../../misc/schema';
|
||||
import { Users } from '..';
|
||||
import { awaitAll } from '../../prelude/await-all';
|
||||
|
||||
export type PackedClip = SchemaType<typeof packedClipSchema>;
|
||||
|
||||
@@ -12,11 +14,15 @@ export class ClipRepository extends Repository<Clip> {
|
||||
): Promise<PackedClip> {
|
||||
const clip = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||
|
||||
return {
|
||||
return await awaitAll({
|
||||
id: clip.id,
|
||||
createdAt: clip.createdAt.toISOString(),
|
||||
userId: clip.userId,
|
||||
user: Users.pack(clip.user || clip.userId),
|
||||
name: clip.name,
|
||||
};
|
||||
description: clip.description,
|
||||
isPublic: clip.isPublic,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,10 +43,30 @@ export const packedClipSchema = {
|
||||
format: 'date-time',
|
||||
description: 'The date that the Clip was created.'
|
||||
},
|
||||
userId: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
format: 'id',
|
||||
},
|
||||
user: {
|
||||
type: 'object' as const,
|
||||
ref: 'User',
|
||||
optional: false as const, nullable: false as const,
|
||||
},
|
||||
name: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'The name of the Clip.'
|
||||
},
|
||||
description: {
|
||||
type: 'string' as const,
|
||||
optional: false as const, nullable: true as const,
|
||||
description: 'The description of the Clip.'
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean' as const,
|
||||
optional: false as const, nullable: false as const,
|
||||
description: 'Whether this Clip is public.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
76
src/server/api/endpoints/clips/add-note.ts
Normal file
76
src/server/api/endpoints/clips/add-note.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import $ from 'cafy';
|
||||
import { ID } from '../../../../misc/cafy-id';
|
||||
import define from '../../define';
|
||||
import { ClipNotes, Clips } from '../../../../models';
|
||||
import { ApiError } from '../../error';
|
||||
import { genId } from '../../../../misc/gen-id';
|
||||
import { getNote } from '../../common/getters';
|
||||
|
||||
export const meta = {
|
||||
tags: ['account', 'notes', 'clips'],
|
||||
|
||||
requireCredential: true as const,
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
params: {
|
||||
clipId: {
|
||||
validator: $.type(ID),
|
||||
},
|
||||
|
||||
noteId: {
|
||||
validator: $.type(ID),
|
||||
},
|
||||
},
|
||||
|
||||
errors: {
|
||||
noSuchClip: {
|
||||
message: 'No such clip.',
|
||||
code: 'NO_SUCH_CLIP',
|
||||
id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf'
|
||||
},
|
||||
|
||||
noSuchNote: {
|
||||
message: 'No such note.',
|
||||
code: 'NO_SUCH_NOTE',
|
||||
id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b'
|
||||
},
|
||||
|
||||
alreadyClipped: {
|
||||
message: 'The note has already been clipped.',
|
||||
code: 'ALREADY_CLIPPED',
|
||||
id: '734806c4-542c-463a-9311-15c512803965'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps, user) => {
|
||||
const clip = await Clips.findOne({
|
||||
id: ps.clipId,
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
if (clip == null) {
|
||||
throw new ApiError(meta.errors.noSuchClip);
|
||||
}
|
||||
|
||||
const note = await getNote(ps.noteId).catch(e => {
|
||||
if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||
throw e;
|
||||
});
|
||||
|
||||
const exist = await ClipNotes.findOne({
|
||||
noteId: note.id,
|
||||
clipId: clip.id
|
||||
});
|
||||
|
||||
if (exist != null) {
|
||||
throw new ApiError(meta.errors.alreadyClipped);
|
||||
}
|
||||
|
||||
await ClipNotes.save({
|
||||
id: genId(),
|
||||
noteId: note.id,
|
||||
clipId: clip.id
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,14 @@ export const meta = {
|
||||
params: {
|
||||
name: {
|
||||
validator: $.str.range(1, 100)
|
||||
},
|
||||
|
||||
isPublic: {
|
||||
validator: $.optional.bool
|
||||
},
|
||||
|
||||
description: {
|
||||
validator: $.optional.nullable.str.range(1, 2048)
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -23,6 +31,8 @@ export default define(meta, async (ps, user) => {
|
||||
createdAt: new Date(),
|
||||
userId: user.id,
|
||||
name: ps.name,
|
||||
isPublic: ps.isPublic,
|
||||
description: ps.description,
|
||||
});
|
||||
|
||||
return await Clips.pack(clip);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import $ from 'cafy';
|
||||
import { ID } from '../../../../misc/cafy-id';
|
||||
import define from '../../define';
|
||||
import { Clips, Notes } from '../../../../models';
|
||||
import { ClipNotes, Clips, Notes } from '../../../../models';
|
||||
import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
||||
import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
|
||||
import { ApiError } from '../../error';
|
||||
|
||||
export const meta = {
|
||||
tags: ['account', 'notes', 'clips'],
|
||||
@@ -14,6 +15,10 @@ export const meta = {
|
||||
kind: 'read:account',
|
||||
|
||||
params: {
|
||||
clipId: {
|
||||
validator: $.type(ID),
|
||||
},
|
||||
|
||||
limit: {
|
||||
validator: $.optional.num.range(1, 100),
|
||||
default: 10
|
||||
@@ -30,7 +35,7 @@ export const meta = {
|
||||
|
||||
errors: {
|
||||
noSuchClip: {
|
||||
message: 'No such list.',
|
||||
message: 'No such clip.',
|
||||
code: 'NO_SUCH_CLIP',
|
||||
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00'
|
||||
}
|
||||
|
||||
@@ -18,6 +18,14 @@ export const meta = {
|
||||
|
||||
name: {
|
||||
validator: $.str.range(1, 100),
|
||||
},
|
||||
|
||||
isPublic: {
|
||||
validator: $.optional.bool
|
||||
},
|
||||
|
||||
description: {
|
||||
validator: $.optional.nullable.str.range(1, 2048)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -42,7 +50,9 @@ export default define(meta, async (ps, user) => {
|
||||
}
|
||||
|
||||
await Clips.update(clip.id, {
|
||||
name: ps.name
|
||||
name: ps.name,
|
||||
description: ps.description,
|
||||
isPublic: ps.isPublic,
|
||||
});
|
||||
|
||||
return await Clips.pack(clip.id);
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -10416,10 +10416,10 @@ vue-prism-editor@1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/vue-prism-editor/-/vue-prism-editor-1.2.2.tgz#023cfd4329848f191aac851f2f5e6c7a8c2e059f"
|
||||
integrity sha512-Lq2VgVygTx3Whn/tC8gD4m1ajA4lzSyCTqPLZA1Dq/ErbBaZA93FWRblwCoDR7AD2nXhGWuiTzb5ih3guzB7DA==
|
||||
|
||||
vue-router@4.0.0-beta.13:
|
||||
version "4.0.0-beta.13"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.0-beta.13.tgz#4611d09a9e44f231cc401ecc294a7f2dcb30e6a6"
|
||||
integrity sha512-dYv9qpHPaojQlfujViiTkPkf1Bf5RCFzkCkdVFc1cENzWJYAGJanpIHiyjyKoM4u7IDFBZMItci+U4ieaEWA8A==
|
||||
vue-router@4.0.0-rc.2:
|
||||
version "4.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.0-rc.2.tgz#8545cab76a05ca4f6dffbe6c6a671a4dbf585ab2"
|
||||
integrity sha512-51mBp39rzBFpk1nyU9SkhPcwR67gBzWIH8p3pyeDmtNYgWzGF3q8MneD/xbMwsfTQkw2H1qBk6uwRaVy3M8Nxw==
|
||||
|
||||
vue-style-loader@4.1.2:
|
||||
version "4.1.2"
|
||||
@@ -10454,10 +10454,10 @@ vuex-persistedstate@3.1.0:
|
||||
deepmerge "^4.2.2"
|
||||
shvl "^2.0.0"
|
||||
|
||||
vuex@4.0.0-beta.4:
|
||||
version "4.0.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.0.0-beta.4.tgz#7b319ead2ef30432b7eaa4e37258ea3c5e44f698"
|
||||
integrity sha512-/+4E1dokq5cwbl4mohOqOj8h0vOLOWmLSqlqTf++bfmN9/JKWtwYfsBrzlK0sYrNfuYcpQeX0BVxQHoHXDfYZQ==
|
||||
vuex@4.0.0-rc.1:
|
||||
version "4.0.0-rc.1"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.0.0-rc.1.tgz#160cd5957972a61c7c01ab585995b78e092a298d"
|
||||
integrity sha512-zgXVCQygF1Sm7ezyudEEMynoV2PBxZdcjE12D0BY1xIKZMrA7GFP6xqADTEAzwfVemXboExJ+/KThfxJFtM/5w==
|
||||
|
||||
w3c-hr-time@^1.0.2:
|
||||
version "1.0.2"
|
||||
|
||||
Reference in New Issue
Block a user