Compare commits
13 Commits
13.0.0-rc.
...
13.0.0-rc.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3ae798d526 | ||
![]() |
e1bd61c70e | ||
![]() |
0296f841c3 | ||
![]() |
bd1f4b8d98 | ||
![]() |
dc19f20153 | ||
![]() |
f5cd809f62 | ||
![]() |
09d5a7806a | ||
![]() |
4606f23ed8 | ||
![]() |
8451e08aaa | ||
![]() |
2047449294 | ||
![]() |
d61eee695f | ||
![]() |
73b62797cd | ||
![]() |
170cfc6a0e |
3
.github/workflows/pr-preview-deploy.yml
vendored
3
.github/workflows/pr-preview-deploy.yml
vendored
@@ -1,7 +1,5 @@
|
|||||||
# Run secret-dependent integration tests only after /deploy approval
|
# Run secret-dependent integration tests only after /deploy approval
|
||||||
on:
|
on:
|
||||||
pull_request:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
repository_dispatch:
|
repository_dispatch:
|
||||||
types: [deploy-command]
|
types: [deploy-command]
|
||||||
|
|
||||||
@@ -12,7 +10,6 @@ jobs:
|
|||||||
deploy-preview-environment:
|
deploy-preview-environment:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if:
|
if:
|
||||||
github.event_name == 'repository_dispatch' &&
|
|
||||||
github.event.client_payload.slash_command.sha != '' &&
|
github.event.client_payload.slash_command.sha != '' &&
|
||||||
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
|
contains(github.event.client_payload.pull_request.head.sha, github.event.client_payload.slash_command.sha)
|
||||||
steps:
|
steps:
|
||||||
|
1
.github/workflows/pr-preview-destroy.yml
vendored
1
.github/workflows/pr-preview-destroy.yml
vendored
@@ -9,6 +9,7 @@ name: Destroy preview environment
|
|||||||
jobs:
|
jobs:
|
||||||
destroy-preview-environment:
|
destroy-preview-environment:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == github.event.pull_request.head.repo.full_name
|
||||||
steps:
|
steps:
|
||||||
- name: Context
|
- name: Context
|
||||||
uses: okteto/context@latest
|
uses: okteto/context@latest
|
||||||
|
30
Dockerfile
30
Dockerfile
@@ -1,4 +1,6 @@
|
|||||||
FROM node:18.13.0-bullseye AS builder
|
ARG NODE_VERSION=18.13.0-bullseye
|
||||||
|
|
||||||
|
FROM node:${NODE_VERSION} AS builder
|
||||||
|
|
||||||
ARG NODE_ENV=production
|
ARG NODE_ENV=production
|
||||||
|
|
||||||
@@ -22,23 +24,29 @@ COPY . ./
|
|||||||
RUN git submodule update --init
|
RUN git submodule update --init
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM node:18.13.0-bullseye-slim AS runner
|
FROM node:${NODE_VERSION}-slim AS runner
|
||||||
|
|
||||||
WORKDIR /misskey
|
ARG UID="991"
|
||||||
|
ARG GID="991"
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
ffmpeg tini \
|
ffmpeg tini \
|
||||||
&& apt-get -y clean \
|
&& apt-get -y clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& groupadd -g "${GID}" misskey \
|
||||||
|
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey
|
||||||
|
|
||||||
COPY --from=builder /misskey/.yarn/install-state.gz ./.yarn/install-state.gz
|
USER misskey
|
||||||
COPY --from=builder /misskey/node_modules ./node_modules
|
WORKDIR /misskey
|
||||||
COPY --from=builder /misskey/built ./built
|
|
||||||
COPY --from=builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
|
COPY --chown=misskey:misskey --from=builder /misskey/.yarn/install-state.gz ./.yarn/install-state.gz
|
||||||
COPY --from=builder /misskey/packages/backend/built ./packages/backend/built
|
COPY --chown=misskey:misskey --from=builder /misskey/node_modules ./node_modules
|
||||||
COPY --from=builder /misskey/packages/frontend/node_modules ./packages/frontend/node_modules
|
COPY --chown=misskey:misskey --from=builder /misskey/built ./built
|
||||||
COPY . ./
|
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
|
||||||
|
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/built ./packages/backend/built
|
||||||
|
COPY --chown=misskey:misskey --from=builder /misskey/packages/frontend/node_modules ./packages/frontend/node_modules
|
||||||
|
COPY --chown=misskey:misskey . ./
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||||
|
@@ -29,8 +29,8 @@ describe('After user signed in', () => {
|
|||||||
|
|
||||||
it('first widget should be removed', () => {
|
it('first widget should be removed', () => {
|
||||||
cy.get('.mk-widget-edit').click();
|
cy.get('.mk-widget-edit').click();
|
||||||
cy.get('.customize-container:first-child .remove._button').click();
|
cy.get('.data-cy-customize-container:first-child .data-cy-customize-container-remove._button').click();
|
||||||
cy.get('.customize-container').should('have.length', 2);
|
cy.get('.data-cy-customize-container').should('have.length', 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildWidgetTest(widgetName) {
|
function buildWidgetTest(widgetName) {
|
||||||
|
@@ -932,6 +932,7 @@ assign: "Zuweisen"
|
|||||||
unassign: "Entfernen"
|
unassign: "Entfernen"
|
||||||
color: "Farbe"
|
color: "Farbe"
|
||||||
manageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
manageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
||||||
|
youCannotCreateAnymore: "Du hast das Erstellungslimit erreicht."
|
||||||
_role:
|
_role:
|
||||||
new: "Rolle erstellen"
|
new: "Rolle erstellen"
|
||||||
edit: "Rolle bearbeiten"
|
edit: "Rolle bearbeiten"
|
||||||
@@ -940,10 +941,10 @@ _role:
|
|||||||
permission: "Rollenberechtigungen"
|
permission: "Rollenberechtigungen"
|
||||||
descriptionOfPermission: "<b>Moderatoren</b> können grundlegende Verwaltungsaufgaben erledigen.\n<b>Administratoren</b> können alle Einstellungen der Instanz verwalten."
|
descriptionOfPermission: "<b>Moderatoren</b> können grundlegende Verwaltungsaufgaben erledigen.\n<b>Administratoren</b> können alle Einstellungen der Instanz verwalten."
|
||||||
assignTarget: "Zuweisungsart"
|
assignTarget: "Zuweisungsart"
|
||||||
descriptionOfAssignTarget: "<b>Manuell</b> bedeutet, dass die Liste der Benutzer einer Rolle manuell verwaltet wird.\n<b>Konditionell</b> bedeutet, dass die Liste der Benutzer einer Rolle durch eine Liste an Konditionen automatisch verwaltet wird."
|
descriptionOfAssignTarget: "<b>Manuell</b> bedeutet, dass die Liste der Benutzer einer Rolle manuell verwaltet wird.\n<b>Konditionell</b> bedeutet, dass die Liste der Benutzer einer Rolle durch eine Bedingung automatisch verwaltet wird."
|
||||||
manual: "Manuell"
|
manual: "Manuell"
|
||||||
conditional: "Konditional"
|
conditional: "Konditional"
|
||||||
condition: "Konditionen"
|
condition: "Bedingung"
|
||||||
isConditionalRole: "Dies ist eine konditionale Rolle."
|
isConditionalRole: "Dies ist eine konditionale Rolle."
|
||||||
isPublic: "Öffentliche Rolle"
|
isPublic: "Öffentliche Rolle"
|
||||||
descriptionOfIsPublic: "Ist dies aktiviert, so kann jeder die Liste der Benutzer, die dieser Rolle zugewiesen sind, einsehen. Zusätzlich wird diese Rolle im Profil zugewiesener Benutzer angezeigt."
|
descriptionOfIsPublic: "Ist dies aktiviert, so kann jeder die Liste der Benutzer, die dieser Rolle zugewiesen sind, einsehen. Zusätzlich wird diese Rolle im Profil zugewiesener Benutzer angezeigt."
|
||||||
@@ -960,13 +961,26 @@ _role:
|
|||||||
canInvite: "Einladungscodes für diese Instanz erstellen"
|
canInvite: "Einladungscodes für diese Instanz erstellen"
|
||||||
canManageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
canManageCustomEmojis: "Benutzerdefinierte Emojis verwalten"
|
||||||
driveCapacity: "Drive-Kapazität"
|
driveCapacity: "Drive-Kapazität"
|
||||||
|
pinMax: "Maximale Anzahl an angehefteten Notizen"
|
||||||
antennaMax: "Maximale Anzahl an Antennen"
|
antennaMax: "Maximale Anzahl an Antennen"
|
||||||
|
wordMuteMax: "Maximale Zeichenlänge für Wortstummschaltungen"
|
||||||
|
webhookMax: "Maximale Anzahl an Webhooks"
|
||||||
|
clipMax: "Maximale Anzahl an Clips"
|
||||||
|
noteEachClipsMax: "Maximale Anzahl an Notizen innerhalb eines Clips"
|
||||||
|
userListMax: "Maximale Anzahl an Benutzern in einer Benutzerliste"
|
||||||
|
userEachUserListsMax: "Maximale Anzahl an Benutzerlisten"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "Lokaler Benutzer"
|
isLocal: "Lokaler Benutzer"
|
||||||
isRemote: "Benutzer fremder Instanz"
|
isRemote: "Benutzer fremder Instanz"
|
||||||
and: "UND"
|
createdLessThan: "Kontoerstellung liegt weniger als X zurück"
|
||||||
or: "ODER"
|
createdMoreThan: "Kontoerstellung liegt mehr als X zurück"
|
||||||
not: "NICHT"
|
followersLessThanOrEq: "Hat X oder weniger Follower"
|
||||||
|
followersMoreThanOrEq: "Hat X oder mehr Follower"
|
||||||
|
followingLessThanOrEq: "Folgt X oder weniger Benutzern"
|
||||||
|
followingMoreThanOrEq: "Folgt X oder mehr Benutzern"
|
||||||
|
and: "UND-Bedingung"
|
||||||
|
or: "ODER-Bedingung"
|
||||||
|
not: "NICHT-Bedingung"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
|
description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
|
||||||
sensitivity: "Erkennungssensitivität"
|
sensitivity: "Erkennungssensitivität"
|
||||||
|
@@ -932,6 +932,7 @@ assign: "Assign"
|
|||||||
unassign: "Unassign"
|
unassign: "Unassign"
|
||||||
color: "Color"
|
color: "Color"
|
||||||
manageCustomEmojis: "Manage Custom Emojis"
|
manageCustomEmojis: "Manage Custom Emojis"
|
||||||
|
youCannotCreateAnymore: "You've hit the creation limit."
|
||||||
_role:
|
_role:
|
||||||
new: "New role"
|
new: "New role"
|
||||||
edit: "Edit role"
|
edit: "Edit role"
|
||||||
@@ -939,11 +940,11 @@ _role:
|
|||||||
description: "Role description"
|
description: "Role description"
|
||||||
permission: "Role permissions"
|
permission: "Role permissions"
|
||||||
descriptionOfPermission: "<b>Moderators</b> can perform basic moderation operations.\n<b>Administrators</b> can change all settings of the instance."
|
descriptionOfPermission: "<b>Moderators</b> can perform basic moderation operations.\n<b>Administrators</b> can change all settings of the instance."
|
||||||
assignTarget: "Assign target"
|
assignTarget: "Assignment type"
|
||||||
descriptionOfAssignTarget: "<b>Manual</b> to manually change who is part of this role and who is not.\n<b>Conditional</b> to have users be automatically assigned and removed from this role based on a set of conditions."
|
descriptionOfAssignTarget: "<b>Manual</b> to manually change who is part of this role and who is not.\n<b>Conditional</b> to have users be automatically assigned and removed from this role based on a condition."
|
||||||
manual: "Manual"
|
manual: "Manual"
|
||||||
conditional: "Conditional"
|
conditional: "Conditional"
|
||||||
condition: "Conditions"
|
condition: "Condition"
|
||||||
isConditionalRole: "This is a conditional role."
|
isConditionalRole: "This is a conditional role."
|
||||||
isPublic: "Public role"
|
isPublic: "Public role"
|
||||||
descriptionOfIsPublic: "Anyone will be able to view a list of users assigned to this role. In addition, this role will be displayed in the profiles of assigned users."
|
descriptionOfIsPublic: "Anyone will be able to view a list of users assigned to this role. In addition, this role will be displayed in the profiles of assigned users."
|
||||||
@@ -960,20 +961,26 @@ _role:
|
|||||||
canInvite: "Create instance invite codes"
|
canInvite: "Create instance invite codes"
|
||||||
canManageCustomEmojis: "Manage Custom Emojis"
|
canManageCustomEmojis: "Manage Custom Emojis"
|
||||||
driveCapacity: "Drive capacity"
|
driveCapacity: "Drive capacity"
|
||||||
|
pinMax: "Maximum number of pinned notes"
|
||||||
antennaMax: "Maximum number of antennas"
|
antennaMax: "Maximum number of antennas"
|
||||||
wordMuteMax: "Maximum number of characters allowed in the word mute string"
|
wordMuteMax: "Maximum number of characters allowed in word mutes"
|
||||||
|
webhookMax: "Maximum number of Webhooks"
|
||||||
|
clipMax: "Maximum number of Clips"
|
||||||
|
noteEachClipsMax: "Maximum number of notes within a clip"
|
||||||
|
userListMax: "Maximum number of user lists"
|
||||||
|
userEachUserListsMax: "Maximum number of users within a user list"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "Local user"
|
isLocal: "Local user"
|
||||||
isRemote: "Remote user"
|
isRemote: "Remote user"
|
||||||
createdLessThan: "Created less than"
|
createdLessThan: "Less than X has passed since account creation"
|
||||||
createdMoreThan: "Created more than"
|
createdMoreThan: "More than X has passed since account creation"
|
||||||
followersLessThanOrEq: "The number of followers is less than or equal to"
|
followersLessThanOrEq: "Has X or fewer followers"
|
||||||
followersMoreThanOrEq: "The number of followers is greater than or equal to"
|
followersMoreThanOrEq: "Has X or more followers"
|
||||||
followingLessThanOrEq: "The number of accounts following is less than or equal to"
|
followingLessThanOrEq: "Follows X or fewer accounts"
|
||||||
followingMoreThanOrEq: "The number of accounts following is greater than or equal to"
|
followingMoreThanOrEq: "Follows X or more accounts"
|
||||||
and: "AND"
|
and: "AND-Condition"
|
||||||
or: "OR"
|
or: "OR-Condition"
|
||||||
not: "NOT"
|
not: "NOT-Condition"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
|
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
|
||||||
sensitivity: "Detection sensitivity"
|
sensitivity: "Detection sensitivity"
|
||||||
|
@@ -966,6 +966,10 @@ _role:
|
|||||||
isRemote: "ผู้ใช้ระยะไกล"
|
isRemote: "ผู้ใช้ระยะไกล"
|
||||||
createdLessThan: "สร้างน้อยกว่า"
|
createdLessThan: "สร้างน้อยกว่า"
|
||||||
createdMoreThan: "สร้างมากกว่า"
|
createdMoreThan: "สร้างมากกว่า"
|
||||||
|
followersLessThanOrEq: "จำนวนผู้ติดตามน้อยกว่าหรือเท่ากับ\n"
|
||||||
|
followersMoreThanOrEq: "จำนวนผู้ติดตามมากกว่าหรือเท่ากับ\n"
|
||||||
|
followingLessThanOrEq: "จำนวนบัญชีต่อไปนี้คือ น้อยกว่าหรือเท่ากับ"
|
||||||
|
followingMoreThanOrEq: "จำนวนบัญชีต่อไปนี้คือ มากกว่าหรือเท่ากับ"
|
||||||
and: "และ"
|
and: "และ"
|
||||||
or: "หรือ"
|
or: "หรือ"
|
||||||
not: "ไม่"
|
not: "ไม่"
|
||||||
|
@@ -932,6 +932,7 @@ assign: "分配"
|
|||||||
unassign: "取消分配"
|
unassign: "取消分配"
|
||||||
color: "颜色"
|
color: "颜色"
|
||||||
manageCustomEmojis: "管理自定义表情符号"
|
manageCustomEmojis: "管理自定义表情符号"
|
||||||
|
youCannotCreateAnymore: "抱歉,您无法再创建更多了。"
|
||||||
_role:
|
_role:
|
||||||
new: "创建角色"
|
new: "创建角色"
|
||||||
edit: "编辑角色"
|
edit: "编辑角色"
|
||||||
@@ -960,9 +961,14 @@ _role:
|
|||||||
canInvite: "发放实例邀请码"
|
canInvite: "发放实例邀请码"
|
||||||
canManageCustomEmojis: "管理自定义表情符号"
|
canManageCustomEmojis: "管理自定义表情符号"
|
||||||
driveCapacity: "网盘容量"
|
driveCapacity: "网盘容量"
|
||||||
|
pinMax: "帖子置顶数量限制"
|
||||||
antennaMax: "可创建的最大天线数量"
|
antennaMax: "可创建的最大天线数量"
|
||||||
wordMuteMax: "屏蔽词的字数限制"
|
wordMuteMax: "屏蔽词的字数限制"
|
||||||
webhookMax: "Webhook 创建数量限制"
|
webhookMax: "Webhook 创建数量限制"
|
||||||
|
clipMax: "便签创建数量限制"
|
||||||
|
noteEachClipsMax: "单个便签内的贴文数量限制"
|
||||||
|
userListMax: "用户列表创建数量限制"
|
||||||
|
userEachUserListsMax: "单个用户列表内用户数量限制"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "是本地用户"
|
isLocal: "是本地用户"
|
||||||
isRemote: "是远程用户"
|
isRemote: "是远程用户"
|
||||||
|
@@ -961,7 +961,8 @@ _role:
|
|||||||
canManageCustomEmojis: "管理自訂表情符號"
|
canManageCustomEmojis: "管理自訂表情符號"
|
||||||
driveCapacity: "雲端硬碟容量"
|
driveCapacity: "雲端硬碟容量"
|
||||||
antennaMax: "可建立的天線數量"
|
antennaMax: "可建立的天線數量"
|
||||||
webhookMax: "可建立的Webhook數"
|
webhookMax: "可建立的Webhook數量"
|
||||||
|
clipMax: "可建立的摘錄數量"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "本地使用者"
|
isLocal: "本地使用者"
|
||||||
isRemote: "遠端使用者"
|
isRemote: "遠端使用者"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "13.0.0-rc.4",
|
"version": "13.0.0-rc.5",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import ms from 'ms';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { DriveFoldersRepository } from '@/models/index.js';
|
import type { DriveFoldersRepository } from '@/models/index.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
@@ -14,6 +15,11 @@ export const meta = {
|
|||||||
|
|
||||||
kind: 'write:drive',
|
kind: 'write:drive',
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 10,
|
||||||
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchFolder: {
|
noSuchFolder: {
|
||||||
message: 'No such folder.',
|
message: 'No such folder.',
|
||||||
|
@@ -6,15 +6,15 @@ import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
import { UserFollowingService } from '@/core/UserFollowingService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '../../error.js';
|
|
||||||
import { GetterService } from '@/server/api/GetterService.js';
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['following', 'users'],
|
tags: ['following', 'users'],
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
max: 100,
|
max: 50,
|
||||||
},
|
},
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
@@ -18,7 +18,7 @@ export const meta = {
|
|||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
max: 300,
|
max: 20,
|
||||||
},
|
},
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import ms from 'ms';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { BlockingsRepository, UserGroupJoiningsRepository, DriveFilesRepository, UserGroupsRepository } from '@/models/index.js';
|
import type { BlockingsRepository, UserGroupJoiningsRepository, DriveFilesRepository, UserGroupsRepository } from '@/models/index.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
@@ -15,6 +16,11 @@ export const meta = {
|
|||||||
|
|
||||||
kind: 'write:messaging',
|
kind: 'write:messaging',
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 120,
|
||||||
|
},
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import ms from 'ms';
|
||||||
import type { NotesRepository, NoteThreadMutingsRepository } from '@/models/index.js';
|
import type { NotesRepository, NoteThreadMutingsRepository } from '@/models/index.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
@@ -14,6 +15,11 @@ export const meta = {
|
|||||||
|
|
||||||
kind: 'write:account',
|
kind: 'write:account',
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 10,
|
||||||
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchNote: {
|
noSuchNote: {
|
||||||
message: 'No such note.',
|
message: 'No such note.',
|
||||||
|
@@ -17,7 +17,7 @@ export const meta = {
|
|||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
max: 300,
|
max: 10,
|
||||||
},
|
},
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import ms from 'ms';
|
||||||
import type { UserGroupsRepository, UserGroupJoiningsRepository } from '@/models/index.js';
|
import type { UserGroupsRepository, UserGroupJoiningsRepository } from '@/models/index.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import type { UserGroup } from '@/models/entities/UserGroup.js';
|
import type { UserGroup } from '@/models/entities/UserGroup.js';
|
||||||
@@ -16,6 +17,11 @@ export const meta = {
|
|||||||
|
|
||||||
description: 'Create a new group.',
|
description: 'Create a new group.',
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 10,
|
||||||
|
},
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@@ -1,34 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="rootEl" class="swhvrteh _popup _shadow" :style="{ zIndex }" @contextmenu.prevent="() => {}">
|
<div ref="rootEl" :class="$style.root" class="_popup _shadow" :style="{ zIndex }" @contextmenu.prevent="() => {}">
|
||||||
<ol v-if="type === 'user'" ref="suggests" class="users">
|
<ol v-if="type === 'user'" ref="suggests" :class="$style.list">
|
||||||
<li v-for="user in users" tabindex="-1" class="user" @click="complete(type, user)" @keydown="onKeydown">
|
<li v-for="user in users" tabindex="-1" :class="$style.item" @click="complete(type, user)" @keydown="onKeydown">
|
||||||
<img class="avatar" :src="user.avatarUrl"/>
|
<img :class="$style.avatar" :src="user.avatarUrl"/>
|
||||||
<span class="name">
|
<span :class="$style.userName">
|
||||||
<MkUserName :key="user.id" :user="user"/>
|
<MkUserName :key="user.id" :user="user"/>
|
||||||
</span>
|
</span>
|
||||||
<span class="username">@{{ acct(user) }}</span>
|
<span>@{{ acct(user) }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li tabindex="-1" class="choose" @click="chooseUser()" @keydown="onKeydown">{{ i18n.ts.selectUser }}</li>
|
<li tabindex="-1" :class="$style.item" @click="chooseUser()" @keydown="onKeydown">{{ i18n.ts.selectUser }}</li>
|
||||||
</ol>
|
</ol>
|
||||||
<ol v-else-if="hashtags.length > 0" ref="suggests" class="hashtags">
|
<ol v-else-if="hashtags.length > 0" ref="suggests" :class="[$style.list, $style.hashtags]">
|
||||||
<li v-for="hashtag in hashtags" tabindex="-1" @click="complete(type, hashtag)" @keydown="onKeydown">
|
<li v-for="hashtag in hashtags" tabindex="-1" :class="$style.item" @click="complete(type, hashtag)" @keydown="onKeydown">
|
||||||
<span class="name">{{ hashtag }}</span>
|
<span class="name">{{ hashtag }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<ol v-else-if="emojis.length > 0" ref="suggests" class="emojis">
|
<ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list">
|
||||||
<li v-for="emoji in emojis" :key="emoji.emoji" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
|
<li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown">
|
||||||
<div class="emoji">
|
<div :class="$style.emoji">
|
||||||
<MkEmoji :emoji="emoji.emoji"/>
|
<MkEmoji :emoji="emoji.emoji"/>
|
||||||
</div>
|
</div>
|
||||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<span v-if="q" class="name" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span>
|
<span v-if="q" :class="$style.emojiName" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span>
|
||||||
<span v-else v-text="emoji.name"></span>
|
<span v-else v-text="emoji.name"></span>
|
||||||
<span v-if="emoji.aliasOf" class="alias">({{ emoji.aliasOf }})</span>
|
<span v-if="emoji.aliasOf" :class="$style.emojiAlias">({{ emoji.aliasOf }})</span>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<ol v-else-if="mfmTags.length > 0" ref="suggests" class="mfmTags">
|
<ol v-else-if="mfmTags.length > 0" ref="suggests" :class="$style.list">
|
||||||
<li v-for="tag in mfmTags" tabindex="-1" @click="complete(type, tag)" @keydown="onKeydown">
|
<li v-for="tag in mfmTags" tabindex="-1" :class="$style.item" @click="complete(type, tag)" @keydown="onKeydown">
|
||||||
<span class="tag">{{ tag }}</span>
|
<span>{{ tag }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
@@ -379,15 +379,16 @@ onBeforeUnmount(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.swhvrteh {
|
.root {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin-top: calc(1em + 8px);
|
margin-top: calc(1em + 8px);
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
transition: top 0.1s ease, left 0.1s ease;
|
transition: top 0.1s ease, left 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
> ol {
|
.list {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
@@ -395,8 +396,9 @@ onBeforeUnmount(() => {
|
|||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
> li {
|
.item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
@@ -404,15 +406,9 @@ onBeforeUnmount(() => {
|
|||||||
overflow: clip;
|
overflow: clip;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
&, * {
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--X3);
|
background: var(--X3);
|
||||||
@@ -420,41 +416,29 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
&[data-selected='true'] {
|
&[data-selected='true'] {
|
||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
|
|
||||||
&, * {
|
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background: var(--accentDarken);
|
background: var(--accentDarken);
|
||||||
|
|
||||||
&, * {
|
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .users > li {
|
.avatar {
|
||||||
|
|
||||||
.avatar {
|
|
||||||
min-width: 28px;
|
min-width: 28px;
|
||||||
min-height: 28px;
|
min-height: 28px;
|
||||||
max-width: 28px;
|
max-width: 28px;
|
||||||
max-height: 28px;
|
max-height: 28px;
|
||||||
margin: 0 8px 0 0;
|
margin: 0 8px 0 0;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.userName {
|
||||||
margin: 0 8px 0 0;
|
margin: 0 8px 0 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
> .emojis > li {
|
.emoji {
|
||||||
|
|
||||||
.emoji {
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0 4px 0 0;
|
margin: 0 4px 0 0;
|
||||||
@@ -463,29 +447,20 @@ onBeforeUnmount(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
> img {
|
.emojiImg {
|
||||||
height: 24px;
|
height: 24px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
object-fit: scale-down;
|
object-fit: scale-down;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
.emojiName {
|
||||||
|
|
||||||
.name {
|
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alias {
|
.emojiAlias {
|
||||||
flex-shrink: 9999999;
|
flex-shrink: 9999999;
|
||||||
margin: 0 0 0 8px;
|
margin: 0 0 0 8px;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .mfmTags > li {
|
|
||||||
|
|
||||||
.name {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -146,6 +146,7 @@ onBeforeUnmount(() => {
|
|||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.root {
|
.root {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MkSpacer :margin-min="20" :margin-max="32">
|
<MkSpacer :margin-min="20" :margin-max="32">
|
||||||
<div class="xkpnjxcv _gaps_m">
|
<div class="_gaps_m">
|
||||||
<template v-for="item in Object.keys(form).filter(item => !form[item].hidden)">
|
<template v-for="item in Object.keys(form).filter(item => !form[item].hidden)">
|
||||||
<MkInput v-if="form[item].type === 'number'" v-model="values[item]" type="number" :step="form[item].step || 1">
|
<MkInput v-if="form[item].type === 'number'" v-model="values[item]" type="number" :step="form[item].step || 1">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
@@ -119,9 +119,3 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.xkpnjxcv {
|
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-google">
|
<div :class="$style.root">
|
||||||
<input v-model="query" type="search" :placeholder="q">
|
<input v-model="query" :class="$style.input" type="search" :placeholder="q">
|
||||||
<button @click="search"><i class="ti ti-search"></i> {{ $ts.searchByGoogle }}</button>
|
<button :class="$style.button" @click="search"><i class="ti ti-search"></i> {{ $ts.searchByGoogle }}</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -19,12 +19,13 @@ const search = () => {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.mk-google {
|
.root {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
> input {
|
.input {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -33,9 +34,9 @@ const search = () => {
|
|||||||
border: solid 1px var(--divider);
|
border: solid 1px var(--divider);
|
||||||
border-radius: 4px 0 0 4px;
|
border-radius: 4px 0 0 4px;
|
||||||
-webkit-appearance: textfield;
|
-webkit-appearance: textfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
> button {
|
.button {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
@@ -46,6 +47,5 @@ const search = () => {
|
|||||||
&:active {
|
&:active {
|
||||||
box-shadow: 0 2px 4px rgba(#000, 0.15) inset;
|
box-shadow: 0 2px 4px rgba(#000, 0.15) inset;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -33,6 +33,7 @@ const modal = $shallowRef<InstanceType<typeof MkModal>>();
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.xubzgfga {
|
.xubzgfga {
|
||||||
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="xubzgfgb" :class="{ cover }" :title="title">
|
<div :class="[$style.root, { [$style.cover]: cover }]" :title="title">
|
||||||
<canvas v-if="!loaded" ref="canvas" :width="size" :height="size" :title="title"/>
|
<canvas v-if="!loaded" ref="canvas" :class="$style.canvas" :width="size" :height="size" :title="title"/>
|
||||||
<img v-if="src" :src="src" :title="title" :alt="alt" @load="onLoad"/>
|
<img v-if="src" :class="$style.img" :src="src" :title="title" :alt="alt" @load="onLoad"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -45,32 +45,32 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.xubzgfgb {
|
.root {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
> canvas,
|
|
||||||
> img {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
> canvas {
|
|
||||||
position: absolute;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
> img {
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.cover {
|
&.cover {
|
||||||
> img {
|
> .img {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.canvas,
|
||||||
|
.img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
position: absolute;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -3,12 +3,12 @@
|
|||||||
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
|
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<template v-for="item in items">
|
<template v-for="item in items">
|
||||||
<button v-if="item.action" v-click-anime class="_button" @click="$event => { item.action($event); close(); }">
|
<button v-if="item.action" v-click-anime class="_button item" @click="$event => { item.action($event); close(); }">
|
||||||
<i class="icon" :class="item.icon"></i>
|
<i class="icon" :class="item.icon"></i>
|
||||||
<div class="text">{{ item.text }}</div>
|
<div class="text">{{ item.text }}</div>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<MkA v-else v-click-anime :to="item.to" @click.passive="close()">
|
<MkA v-else v-click-anime :to="item.to" class="item" @click.passive="close()">
|
||||||
<i class="icon" :class="item.icon"></i>
|
<i class="icon" :class="item.icon"></i>
|
||||||
<div class="text">{{ item.text }}</div>
|
<div class="text">{{ item.text }}</div>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
||||||
@@ -66,6 +66,7 @@ function close() {
|
|||||||
.szkkfdyq {
|
.szkkfdyq {
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
width: min(460px, 100vw);
|
width: min(460px, 100vw);
|
||||||
|
margin: auto;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -82,11 +83,11 @@ function close() {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main, > .sub {
|
> .main {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
|
|
||||||
> * {
|
> .item {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -128,11 +129,5 @@ function close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .sub {
|
|
||||||
margin-top: 8px;
|
|
||||||
padding-top: 8px;
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1,17 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkA v-if="url.startsWith('/')" v-user-preview="canonical" class="akbvjaqn" :class="{ isMe }" :to="url" :style="{ background: bgCss }">
|
<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }">
|
||||||
<img class="icon" :src="`/avatar/@${username}@${host}`" alt="">
|
<img :class="$style.icon" :src="`/avatar/@${username}@${host}`" alt="">
|
||||||
<span class="main">
|
<span>
|
||||||
<span class="username">@{{ username }}</span>
|
<span :class="$style.username">@{{ username }}</span>
|
||||||
<span v-if="(host != localHost) || $store.state.showFullAcct" class="host">@{{ toUnicode(host) }}</span>
|
<span v-if="(host != localHost) || $store.state.showFullAcct" :class="$style.host">@{{ toUnicode(host) }}</span>
|
||||||
</span>
|
</span>
|
||||||
</MkA>
|
</MkA>
|
||||||
<a v-else class="akbvjaqn" :href="url" target="_blank" rel="noopener" :style="{ background: bgCss }">
|
|
||||||
<span class="main">
|
|
||||||
<span class="username">@{{ username }}</span>
|
|
||||||
<span class="host">@{{ toUnicode(host) }}</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -39,8 +33,8 @@ bg.setAlpha(0.1);
|
|||||||
const bgCss = bg.toRgbString();
|
const bgCss = bg.toRgbString();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.akbvjaqn {
|
.root {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 4px 8px 4px 4px;
|
padding: 4px 8px 4px 4px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
@@ -49,18 +43,18 @@ const bgCss = bg.toRgbString();
|
|||||||
&.isMe {
|
&.isMe {
|
||||||
color: var(--mentionMe);
|
color: var(--mentionMe);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .icon {
|
.icon {
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
margin: 0 0.2em 0 0;
|
margin: 0 0.2em 0 0;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main > .host {
|
.host {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -7,9 +7,9 @@
|
|||||||
:leave-to-class="$style['transition_' + transitionName + '_leaveTo']"
|
:leave-to-class="$style['transition_' + transitionName + '_leaveTo']"
|
||||||
:duration="transitionDuration" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="onOpened"
|
:duration="transitionDuration" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="onOpened"
|
||||||
>
|
>
|
||||||
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog' || type === 'dialog:top', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
||||||
<div class="_modalBg" :class="[$style.bg, { [$style.bgTransparent]: transparentBg && (type === 'popup') }]" :style="{ zIndex }" @click="onBgClick" @mousedown="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
|
<div class="_modalBg" :class="[$style.bg, { [$style.bgTransparent]: transparentBg && (type === 'popup') }]" :style="{ zIndex }" @click="onBgClick" @mousedown="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
|
||||||
<div ref="content" :class="[$style.content, { [$style.fixed]: fixed, [$style.top]: type === 'dialog:top' }]" :style="{ zIndex }" @click.self="onBgClick">
|
<div ref="content" :class="[$style.content, { [$style.fixed]: fixed }]" :style="{ zIndex }" @click.self="onBgClick">
|
||||||
<slot :max-height="maxHeight" :type="type"></slot>
|
<slot :max-height="maxHeight" :type="type"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,7 +33,7 @@ function getFixedContainer(el: Element | null): Element | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModalTypes = 'popup' | 'dialog' | 'dialog:top' | 'drawer';
|
type ModalTypes = 'popup' | 'dialog' | 'drawer';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
manualShowing?: boolean | null;
|
manualShowing?: boolean | null;
|
||||||
@@ -413,16 +413,6 @@ defineExpose({
|
|||||||
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
|
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
|
||||||
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
|
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:global > * {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.top {
|
|
||||||
&:global > * {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,10 +440,6 @@ defineExpose({
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
&:global > * {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -117,6 +117,7 @@ function onContextmenu(ev: MouseEvent) {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.hrmcaedk {
|
.hrmcaedk {
|
||||||
|
margin: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@@ -85,6 +85,7 @@ defineExpose({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.ebkgoccj {
|
.ebkgoccj {
|
||||||
|
margin: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :prefer-type="'dialog:top'" @click="modal.close()" @closed="onModalClosed()">
|
<MkModal ref="modal" :prefer-type="'dialog'" @click="modal.close()" @closed="onModalClosed()">
|
||||||
<MkPostForm ref="form" v-bind="props" autofocus freeze-after-posted @posted="onPosted" @cancel="modal.close()" @esc="modal.close()"/>
|
<MkPostForm ref="form" style="margin: 0 auto auto auto;" v-bind="props" autofocus freeze-after-posted @posted="onPosted" @cancel="modal.close()" @esc="modal.close()"/>
|
||||||
</MkModal>
|
</MkModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.root {
|
.root {
|
||||||
|
margin: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
|
@@ -37,6 +37,7 @@ watch(() => props.showing, () => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.iuyakobc {
|
.iuyakobc {
|
||||||
|
margin: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@@ -19,9 +19,9 @@
|
|||||||
@update:model-value="v => emit('updateWidgets', v)"
|
@update:model-value="v => emit('updateWidgets', v)"
|
||||||
>
|
>
|
||||||
<template #item="{element}">
|
<template #item="{element}">
|
||||||
<div :class="[$style.widget, $style['customize-container']]">
|
<div :class="[$style.widget, $style['customize-container']]" class="data-cy-customize-container">
|
||||||
<button :class="$style['customize-container-config']" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button>
|
<button :class="$style['customize-container-config']" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button>
|
||||||
<button :class="$style['customize-container-remove']" class="_button" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button>
|
<button :class="$style['customize-container-remove']" class="_button data-cy-customize-container-remove" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button>
|
||||||
<div class="handle">
|
<div class="handle">
|
||||||
<component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @update-props="updateWidget(element.id, $event)"/>
|
<component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @update-props="updateWidget(element.id, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -172,6 +172,7 @@ hr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
._button {
|
._button {
|
||||||
|
@extend ._noSelect;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -188,14 +189,6 @@ hr {
|
|||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
&, * {
|
|
||||||
@extend ._noSelect;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user