Compare commits
375 Commits
Author | SHA1 | Date | |
---|---|---|---|
c40b630530 | |||
7fc0698ecf | |||
4f3c8b940e | |||
1855ab60f1 | |||
af4f1a7bd6 | |||
8646a9c49c | |||
8d7c033cf5 | |||
b8900e32de | |||
d48c25d2c9 | |||
a87c5899c5 | |||
147ad69864 | |||
c146006476 | |||
a0f10d7ca1 | |||
299b91edc4 | |||
95c89ca6db | |||
7fe0d71e7f | |||
fbbb506e86 | |||
ec80b06a45 | |||
41e1619f1f | |||
ba6a9c6a93 | |||
18571c52fb | |||
5d5dfeaa83 | |||
3669d8c0f3 | |||
69d72819c6 | |||
54dcc10250 | |||
1edfce8f73 | |||
675e573a8c | |||
1080fa63a9 | |||
8047086988 | |||
449b9f7fa0 | |||
b7a15bf6ca | |||
7c3873887d | |||
247ea4cf12 | |||
0b7af5c669 | |||
2b62a4e2e5 | |||
65bfa3c0d6 | |||
84db15694d | |||
746189ba37 | |||
74e845b3ac | |||
90fe70540e | |||
f28af75191 | |||
924bb2bc70 | |||
19d60f3d51 | |||
6903476868 | |||
cf0dccc209 | |||
cfd959129d | |||
819287951c | |||
e136193925 | |||
8c631864d9 | |||
d7d0f6ae2e | |||
b83b3fb9d1 | |||
dfce5bc0af | |||
3487ddabea | |||
2dbff75e7a | |||
02465ded9f | |||
ffcd387945 | |||
4806346707 | |||
31c3f6abf7 | |||
83e47fdd60 | |||
340ce7fa4c | |||
ac86fee9b4 | |||
6dfa283d7a | |||
0cce8a4d21 | |||
1c6d9ab2ef | |||
6ca265e579 | |||
c612c4bf18 | |||
481a791a60 | |||
cb516c2943 | |||
c0abd6f0c0 | |||
47695ed685 | |||
4ca8020ef5 | |||
bfac83d5b8 | |||
4cd2e55fd3 | |||
61c7e7bc48 | |||
bef41718e2 | |||
5b4b52bb97 | |||
8901b6d774 | |||
e3a24e9215 | |||
a515c1f53e | |||
2e22874dec | |||
30f0b1c30d | |||
600aea4dbb | |||
f5d53d784d | |||
1061e1f7ae | |||
1d5fc04aa6 | |||
d1cf0c7998 | |||
84218abf2b | |||
5bebdb2511 | |||
9c8e9b4165 | |||
7b786bfde3 | |||
42a08642a4 | |||
e88f7ca7b2 | |||
c26ed1421b | |||
ed2f94a3c1 | |||
daba7fe87c | |||
afc9caf7bf | |||
67697a7aa6 | |||
1623d9e70c | |||
c304351335 | |||
c1520763c6 | |||
4853bc9414 | |||
e7c865f8e3 | |||
46cb377bc2 | |||
373a5ba3e1 | |||
3bedef67c8 | |||
17ea19ada8 | |||
1f5b2285fd | |||
17f0001966 | |||
04ba09a6af | |||
70d2744319 | |||
6b2f0929ec | |||
f2629bd3f2 | |||
9e6c29c3c0 | |||
abda973094 | |||
86b08dd5bd | |||
617e331f0f | |||
cc438a9372 | |||
b0fb218bfd | |||
fc85a607e6 | |||
fb244c45e3 | |||
c123784c54 | |||
342a5276fc | |||
51a32846ee | |||
35865429a8 | |||
aadd5b95b8 | |||
f9f2ca51ac | |||
1cb93a8c10 | |||
7e5dbb2ba5 | |||
2772e3d80e | |||
223c578734 | |||
d01315dee2 | |||
7dafb4ce4c | |||
9671db9b14 | |||
bec559f67c | |||
14053c1394 | |||
55e4b1c828 | |||
dda3421159 | |||
45e7488e60 | |||
30c7bd66b7 | |||
af4f5bdac0 | |||
3d1a8cc341 | |||
0e52fb2544 | |||
e6d6c0a17c | |||
cfd2d47e00 | |||
83301a879d | |||
d7881ba129 | |||
b9fef1edf7 | |||
2c606f7b23 | |||
03797607ed | |||
254b7f500d | |||
51edd51bf2 | |||
0d403f4a3f | |||
0fa134addd | |||
7002270084 | |||
1c5452d047 | |||
f0d62c07bf | |||
496ca55bba | |||
79cfba226b | |||
f69b60dffe | |||
513385133f | |||
6f1e2f6636 | |||
8ae94c034d | |||
cd9696f25e | |||
d62a6bab41 | |||
20df002746 | |||
fa6b01546e | |||
91b37a6e52 | |||
d8171d7c8b | |||
fa96e2daf1 | |||
87708c3b84 | |||
6319023cc9 | |||
efad9d1b60 | |||
a1dea657fa | |||
6b1b75717b | |||
efe08e0bd3 | |||
62892c4894 | |||
0c2a62da11 | |||
5bc9e9aadd | |||
112c33d35b | |||
864da3030f | |||
f2e719b361 | |||
6aab515389 | |||
819b535ab0 | |||
60e95ac2ac | |||
9b94ddff0a | |||
174f8022eb | |||
ddc3c5ba68 | |||
a7e6b766be | |||
befc35a3ac | |||
2e9bbf389e | |||
80b5fda292 | |||
c48cbd95f6 | |||
931bdc6aac | |||
7f81506c8b | |||
b4b9e76c8d | |||
e5a3dcf868 | |||
825648535c | |||
5cbc908ba3 | |||
895cf53ee1 | |||
e41f74e77c | |||
c21caad1c5 | |||
86fcd3a378 | |||
2b3687b3cb | |||
5d61c7c691 | |||
1bb266e7c7 | |||
1fca8d322c | |||
325cd03a59 | |||
2f7e6baa05 | |||
d252e066fe | |||
fe7bd9ab3c | |||
84e3f41305 | |||
3e8cccad0d | |||
a2b94d67f7 | |||
6ab61e73b0 | |||
051c6973af | |||
806a49ec3d | |||
3829fe128a | |||
649177985d | |||
c15148b23c | |||
261a3f5d91 | |||
256ba78ba5 | |||
04aff8866e | |||
1a51b98700 | |||
f64100226d | |||
b7805e48a6 | |||
0d9556620d | |||
a51828a7a2 | |||
7e2009f408 | |||
008d950a39 | |||
22d5862afb | |||
de569147a5 | |||
a82c3db750 | |||
80706d10af | |||
93f01ed4df | |||
a3a28e5557 | |||
8948a0d3a4 | |||
d849ea9b41 | |||
0144575f3f | |||
bdbe646ca7 | |||
1a1483a242 | |||
962346785b | |||
a73da3cd70 | |||
9c27d0ae3f | |||
525d5218c1 | |||
e23b13ec7f | |||
29b000e03c | |||
6a7b0df810 | |||
4142de9195 | |||
9195e1be00 | |||
75382d13fd | |||
d444280a28 | |||
52fc0fe04a | |||
216bebadf1 | |||
a5592931cb | |||
a2228417ff | |||
3e1e292c3e | |||
f2f039ae9e | |||
29dde1eda0 | |||
45d3792ce0 | |||
875d0aaebb | |||
26c9d8ff6f | |||
5e3372e932 | |||
f7069dcd18 | |||
560bb65384 | |||
50cd6a036e | |||
441ab2b5f8 | |||
ba5ed188a1 | |||
72e672f08d | |||
120474ec6a | |||
eee57c47f5 | |||
4c160869b8 | |||
3720a7fbe0 | |||
7afa541a53 | |||
6f979c8275 | |||
d399241e65 | |||
e85dec030a | |||
d0220764cc | |||
75c1df9531 | |||
bca7156d6b | |||
64277b7157 | |||
4a72543f65 | |||
5b84d29807 | |||
a11061ec2b | |||
24cfb93b2e | |||
502b42d63a | |||
612672b79c | |||
abc670e1b1 | |||
d589ccdd01 | |||
acb07d9f7d | |||
f4d2186719 | |||
d0ede5c665 | |||
554cbb5e9b | |||
dbd32a56bf | |||
7f500235c6 | |||
39a58084c8 | |||
cde0fde836 | |||
e70cca0fda | |||
919bd7eb82 | |||
312cff3d6f | |||
0d86eef3d7 | |||
13acf570e7 | |||
fa17623fa8 | |||
06fd525950 | |||
4805b5115a | |||
108dcb3e61 | |||
780d272535 | |||
02ea4b81a5 | |||
7c1bdc6d36 | |||
78c7b8b836 | |||
227da30acb | |||
610805026f | |||
c02399c3d2 | |||
e0799d4153 | |||
6df83f1aa9 | |||
efb5ad1d9b | |||
716976f016 | |||
7892f41b84 | |||
d549e03b3f | |||
c511ef21ff | |||
d64dc45899 | |||
bcb0588409 | |||
0975959eb9 | |||
e985a6d9d3 | |||
b893305974 | |||
724fdd44e4 | |||
b480ef669c | |||
4b145da046 | |||
83d168ece3 | |||
ae44fe7818 | |||
f8981b3acb | |||
050b324885 | |||
e74c0df6c6 | |||
22d0d11895 | |||
80d0c0cf74 | |||
518646b925 | |||
479d7e0087 | |||
8ea1a555f4 | |||
04024dc37c | |||
060ff9288f | |||
197116ee78 | |||
a1e0015257 | |||
7e701ef9e0 | |||
3d6fb661bb | |||
fc372496da | |||
ad7258fe9c | |||
bd707cb2a8 | |||
1839b5f205 | |||
02b47f963c | |||
f8a7f9378a | |||
65cb253be4 | |||
a12356b24b | |||
6a67ad7f93 | |||
140a7f0b1c | |||
00159bc6b5 | |||
9542260103 | |||
72074578df | |||
3b4750a988 | |||
aeec5f0163 | |||
9c94d8c8d6 | |||
581712a2c8 | |||
b25b51aaca | |||
fb97e13a61 | |||
36e154fdb2 | |||
ca273a24b4 | |||
d828bf2889 | |||
87efccef18 | |||
e0bf522e7f | |||
5b1cd3bd3c | |||
f00489196d | |||
dd53bf7e51 | |||
35a6da26d2 | |||
c8c8748a0b | |||
46d0065a90 | |||
990b0180a8 | |||
f3bfb72251 |
@ -9,6 +9,7 @@ mongodb:
|
||||
db: test-misskey
|
||||
user: admin
|
||||
pass: ''
|
||||
# __REDIS__
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
137
.circleci/config.yml
Normal file
137
.circleci/config.yml
Normal file
@ -0,0 +1,137 @@
|
||||
version: 2.1
|
||||
|
||||
general:
|
||||
branches:
|
||||
ignore:
|
||||
- l10n_develop
|
||||
- imgbot
|
||||
|
||||
executors:
|
||||
default:
|
||||
working_directory: /tmp/workspace
|
||||
docker:
|
||||
- image: misskey/ci:latest
|
||||
- image: circleci/mongo:latest
|
||||
- image: circleci/redis:latest
|
||||
docker:
|
||||
working_directory: /tmp/workspace
|
||||
docker:
|
||||
- image: docker:latest
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: default
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore npm package caches
|
||||
keys:
|
||||
- npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-
|
||||
- npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-
|
||||
- npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-
|
||||
- npm-v1-arch-{{ arch }}-
|
||||
- npm-v1-
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: |
|
||||
npm install
|
||||
- run:
|
||||
name: Configure
|
||||
command: |
|
||||
cp .ci/default.yml .config
|
||||
cp .ci/test.yml .config
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
npm run build || (echo -e '\033[0;34mRebuild modules\033[0;39m' && ls -1A node_modules | grep '^[^@]' | xargs npm rebuild && ls -1A node_modules | grep '^@' | xargs -I%1 sh -c 'ls -1A node_modules/'%1' | xargs -P0 -I%2 npm rebuild node_modules/'%1'/%2' && npm run build)
|
||||
ls -1ARl node_modules > ls
|
||||
- save_cache:
|
||||
name: Cache npm packages
|
||||
key: npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-ls-{{ checksum "ls" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- store_artifacts:
|
||||
path: built
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- .
|
||||
test:
|
||||
parameters:
|
||||
without_redis:
|
||||
type: string
|
||||
default: ""
|
||||
executor: default
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- when:
|
||||
condition: <<parameters.without_redis>>
|
||||
steps:
|
||||
- run:
|
||||
name: Configure
|
||||
command: |
|
||||
mv .config/test.yml .config/test_redis.yml
|
||||
touch .config/test.yml
|
||||
cat .config/test_redis.yml | while IFS= read line; do if [[ "$line" = '# __REDIS__' ]]; then break; else echo "$line" >> .config/test.yml; fi; done
|
||||
- run:
|
||||
name: Test
|
||||
command: |
|
||||
npm run test || (npm rebuild && npm run test) || ((node-gyp configure && node-gyp build && npm run build || (echo -e '\033[0;34mRebuild modules\033[0;39m' && ls -1A node_modules | grep '^[^@]' | xargs npm rebuild && ls -1A node_modules | grep '^@' | xargs -I%1 sh -c 'ls -1A node_modules/'%1' | xargs -P0 -I%2 npm rebuild node_modules/'%1'/%2' && npm run build)) && npm run test)
|
||||
ls -1ARl node_modules > ls
|
||||
- save_cache:
|
||||
name: Cache npm packages
|
||||
key: npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-ls-{{ checksum "ls" }}
|
||||
paths:
|
||||
- node_modules
|
||||
|
||||
docker:
|
||||
parameters:
|
||||
with_deploy:
|
||||
type: string
|
||||
default: ""
|
||||
executor: docker
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
docker build . | tee docker.log
|
||||
tail -n 1 docker.log | read __Successfully __built tag
|
||||
- when:
|
||||
condition: <<parameters.with_deploy>>
|
||||
steps:
|
||||
- run:
|
||||
name: Deploy
|
||||
command: |
|
||||
if [ "$DOCKERHUB_USERNAME$DOCKERHUB_PASSWORD" ]
|
||||
then
|
||||
docker tag $tag misskey/misskey
|
||||
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
|
||||
docker push misskey/misskey
|
||||
else
|
||||
echo -e '\033[0;33mAborted deploying to Docker Hub\033[0;39m'
|
||||
fi
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-and-test:
|
||||
jobs:
|
||||
- build
|
||||
- test:
|
||||
requires:
|
||||
- build
|
||||
- test:
|
||||
without_redis: "true"
|
||||
requires:
|
||||
- build
|
||||
- docker:
|
||||
filters:
|
||||
branches:
|
||||
ignore: master
|
||||
- docker:
|
||||
with_deploy: "true"
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
@ -1,6 +1,3 @@
|
||||
name: example-instance-name # Name of your instance
|
||||
description: example-description # Description of your instance
|
||||
|
||||
maintainer:
|
||||
name: example-maitainer-name # Your name
|
||||
url: http://example.com/ # Your contact (http or mailto)
|
||||
@ -25,7 +22,7 @@ url: https://example.tld/
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
# You need to setup reverse proxy. (eg. Nginx)
|
||||
# You need to setup reverse proxy. (eg. nginx)
|
||||
# You do not define 'https' section.
|
||||
|
||||
# Option 2: Standalone
|
||||
@ -148,6 +145,12 @@ drive:
|
||||
# consumer_key: example-twitter-consumer-key
|
||||
# consumer_secret: example-twitter-consumer-secret-key
|
||||
|
||||
# GitHub integration
|
||||
# You need to set the oauth callback url as : https://<your-misskey-instance>/api/gh/cb
|
||||
#github:
|
||||
# client_id: example-github-client-id
|
||||
# client_secret: example-github-client-secret
|
||||
|
||||
# Ghost
|
||||
# Ghost account is an account used for the purpose of delegating
|
||||
# followers when putting users in the list.
|
||||
|
@ -35,7 +35,7 @@ before_script:
|
||||
- npm install
|
||||
|
||||
# 設定ファイルを配置
|
||||
- cp ./.travis/default.yml ./.config
|
||||
- cp ./.travis/test.yml ./.config
|
||||
- cp ./.ci/default.yml ./.config
|
||||
- cp ./.ci/test.yml ./.config
|
||||
|
||||
- travis_wait npm run build
|
||||
|
24
Dockerfile
24
Dockerfile
@ -3,8 +3,9 @@ FROM alpine:3.8 AS base
|
||||
ENV NODE_ENV=production
|
||||
|
||||
RUN apk add --no-cache nodejs nodejs-npm zlib
|
||||
RUN npm i -g npm@latest
|
||||
|
||||
WORKDIR /misskey
|
||||
COPY . ./
|
||||
|
||||
FROM base AS builder
|
||||
|
||||
@ -21,18 +22,23 @@ RUN apk add --no-cache \
|
||||
pkgconfig \
|
||||
libtool \
|
||||
zlib-dev
|
||||
RUN npm install \
|
||||
&& npm install -g node-gyp \
|
||||
&& node-gyp configure \
|
||||
&& node-gyp build \
|
||||
&& npm run build
|
||||
RUN npm i -g node-gyp
|
||||
|
||||
COPY ./package.json ./
|
||||
RUN npm i
|
||||
|
||||
COPY . ./
|
||||
RUN node-gyp configure \
|
||||
&& node-gyp build \
|
||||
&& npm run build
|
||||
|
||||
FROM base AS runner
|
||||
|
||||
COPY --from=builder /misskey/built ./built
|
||||
COPY --from=builder /misskey/node_modules ./node_modules
|
||||
|
||||
RUN apk add --no-cache tini
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
|
||||
COPY --from=builder /misskey/node_modules ./node_modules
|
||||
COPY --from=builder /misskey/built ./built
|
||||
COPY . ./
|
||||
|
||||
CMD ["npm", "start"]
|
||||
|
30
README.md
30
README.md
@ -3,6 +3,7 @@
|
||||
[](https://misskey.xyz/)
|
||||
================================================================
|
||||
|
||||
[](https://circleci.com/gh/syuilo/misskey)
|
||||
[![][travis-badge]][travis-link]
|
||||
[![][dependencies-badge]][dependencies-link]
|
||||
[](http://makeapullrequest.com)
|
||||
@ -71,39 +72,46 @@ Please see [Contribution guide](./CONTRIBUTING.md).
|
||||
----------------------------------------------------------------
|
||||
<!-- PATREON_START -->
|
||||
<table><tr>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=CXe9AqlZy9AsYfiWd3OBYVOzvODoN47Litz0Tu4BFpU%3D" alt="Gargron"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1?token-time=2145916800&token-hash=d6P5MWHHsCMxUuBAEPAoVc5wLUR19mIhqAq7Ma9h9rI%3D" alt="ne_moni"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/2?token-time=2145916800&token-hash=mgPdX9TqZxEg4TTPuc477dxhIgYk9246qafjWZEqZ7g%3D" alt="Melilot"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/2?token-time=2145916800&token-hash=rwZ8qvbm_kpA4ib3kc07tVKupXeySpY5ATQFGxfL9v0%3D" alt="Xeltica"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1?token-time=2145916800&token-hash=I8lJVM8LeW6TSo5W6uIIRZ42cw83zp1wK_FsbzY0mcQ%3D" alt="mydarkstar"></td>
|
||||
<td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
|
||||
<td><a href="https://www.patreon.com/negao">negao</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
|
||||
<td><a href="https://www.patreon.com/AxellaMC">Xeltica</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td>
|
||||
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
||||
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3?token-time=2145916800&token-hash=qsdn0-e6yLaLI6hUX9JAkyTR6a5UdnSp7T1foniBvGQ%3D" alt="YUKIMOCHI"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/8241184/39e18850e87a449e9c9a71acb3310ebd/2?token-time=2145916800&token-hash=iUXOQzRyJDv3PJxwS7Mjwg1459dzh2trOq6NFtXu_OM%3D" alt="Acid Chicken"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/10789744/97175095d8f04c0f86225ff47cb98d40/1?token-time=2145916800&token-hash=P4BIzCX2I1CkEP66ottfhsC8Wr6BUSamjA-vq3pLqFI%3D" alt="Naoki Hirayama"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=tB1e_r8RlZ5sFL0KV_e8dugapxatNBRK1Z3h67TO1g8%3D" alt="Gargron"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1?token-time=2145916800&token-hash=VZUtwrjQa8Jml4twCjHYQQZ64wHEY4oIlGl7Kc-VYUQ%3D" alt="Nokotaro Takeda"></td>
|
||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
|
||||
</tr><tr>
|
||||
<td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
|
||||
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
|
||||
<td><a href="https://www.patreon.com/acid_chicken">Acid Chicken</a></td>
|
||||
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
|
||||
<td><a href="https://www.patreon.com/spinlock">Naoki Hirayama</a></td>
|
||||
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
|
||||
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
|
||||
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
|
||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
</tr><tr>
|
||||
</tr></table>
|
||||
|
||||
**Last updated:** Tue, 02 Oct 2018 09:25:07 UTC
|
||||
**Last updated:** Wed, 31 Oct 2018 23:21:06 UTC
|
||||
<!-- PATREON_END -->
|
||||
|
||||
:four_leaf_clover: Copyright
|
||||
|
38
appveyor.yml
38
appveyor.yml
@ -1,38 +0,0 @@
|
||||
# appveyor file
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: 11.0.0
|
||||
|
||||
platform:
|
||||
- x64
|
||||
- Any CPU
|
||||
|
||||
build: off
|
||||
|
||||
install:
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
|
||||
# Update node-gyp
|
||||
# 必須! node-gyp のバージョンを上げないと、ネイティブモジュールのコンパイルに失敗します
|
||||
- npm install -g node-gyp
|
||||
|
||||
- npm install
|
||||
|
||||
init:
|
||||
# git clone の際の改行を変換しないようにします
|
||||
- git config --global core.autocrlf false
|
||||
|
||||
before_test:
|
||||
# 設定ファイルを配置
|
||||
- cp ./.travis/default.yml ./.config
|
||||
- cp ./.travis/test.yml ./.config
|
||||
|
||||
- npm run build
|
||||
|
||||
test_script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm test
|
@ -1,13 +0,0 @@
|
||||
const deleteUser = require('../built/models/user').deleteUser;
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const userId = args[0];
|
||||
|
||||
console.log(`deleting ${userId}...`);
|
||||
|
||||
deleteUser(userId).then(() => {
|
||||
console.log('done');
|
||||
}, e => {
|
||||
console.error(e);
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
const mongo = require('mongodb');
|
||||
const User = require('../built/models/user').default;
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const user = args[0];
|
||||
|
||||
const q = user.startsWith('@') ? {
|
||||
username: user.split('@')[1],
|
||||
host: user.split('@')[2] || null
|
||||
} : { _id: new mongo.ObjectID(user) };
|
||||
|
||||
console.log(`Mark as verfied ${user}...`);
|
||||
|
||||
User.update(q, {
|
||||
$set: {
|
||||
isVerified: true
|
||||
}
|
||||
}).then(() => {
|
||||
console.log(`Done ${user}`);
|
||||
}, e => {
|
||||
console.error(e);
|
||||
});
|
@ -1,42 +0,0 @@
|
||||
const { default: Note } = require('../built/models/note');
|
||||
const { default: Meta } = require('../built/models/meta');
|
||||
const { default: User } = require('../built/models/user');
|
||||
|
||||
async function main() {
|
||||
const meta = await Meta.findOne({});
|
||||
|
||||
const notesCount = await Note.count();
|
||||
|
||||
const usersCount = await User.count();
|
||||
|
||||
const originalNotesCount = await Note.count({
|
||||
'_user.host': null
|
||||
});
|
||||
|
||||
const originalUsersCount = await User.count({
|
||||
host: null
|
||||
});
|
||||
|
||||
const stats = {
|
||||
notesCount,
|
||||
usersCount,
|
||||
originalNotesCount,
|
||||
originalUsersCount
|
||||
};
|
||||
|
||||
if (meta) {
|
||||
await Meta.update({}, {
|
||||
$set: {
|
||||
stats
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await Meta.insert({
|
||||
stats
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
main().then(() => {
|
||||
console.log('done');
|
||||
}).catch(console.error);
|
@ -18,6 +18,10 @@ If you find an untranslated part on Misskey:
|
||||
4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes.
|
||||
- For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja-JP.yml`.
|
||||
|
||||
5. And done!
|
||||
5. When you add text to the ja-JP file (of syuilo/misskey), it will automatically be applied to all other local language files within 24-48 hours. Translations added in ja-JP file should contain the original Japanese strings (example see step 4).
|
||||
|
||||
6. The new strings will automatically appear in the localized language files in the original Japanese text. After that, please go to [CrowdIn](https://crowdin.com/project/misskey) to do the localized translations in your language.
|
||||
|
||||
7. And done!
|
||||
|
||||
For more details, please refer to this [commit](https://github.com/syuilo/misskey/commit/10f6d5980fa7692ccb45fbc5f843458b69b7607c).
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "Nach links schichten"
|
||||
pop-right: "Rechts andocken"
|
||||
dev: "Fehler beim Erstellen der Applikation. Bitte versuche es erneut."
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "Profil"
|
||||
notification: "Mitteilungen"
|
||||
apps: "In App öffnen"
|
||||
mute: "Stummschalten"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "Sicherheit"
|
||||
signin: "サインイン履歴"
|
||||
password: "Passwort"
|
||||
@ -847,28 +849,39 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "Bitte Passwort eingeben"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
reset: "Passwort ändern"
|
||||
enter-current-password: "Derzeitiges Passwort eingeben"
|
||||
enter-new-password: "Neues Passwort eingeben"
|
||||
enter-new-password-again: "Neues Passwort erneut eingeben"
|
||||
not-match: "Passwörter stimmen nicht überein."
|
||||
changed: "Passwort geändert"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
enter-new-password-again: "もう一度新しいパスワードを入力してください"
|
||||
not-match: "新しいパスワードが一致しません"
|
||||
changed: "パスワードを変更しました"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "この投稿は非公開です"
|
||||
deleted: "この投稿は削除されました"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "Stack to the left"
|
||||
pop-right: "Dock on the right"
|
||||
dev: "Failed to create the application. Please try again."
|
||||
ai-chan-kawaii: "Ai-chan kawaii!"
|
||||
auth/views/form.vue:
|
||||
share-access: "Would you <b>allow</b> <i>{{ app.name }}</i> to access your account?"
|
||||
permission-ask: "This application requires the following permissions:"
|
||||
@ -249,7 +250,7 @@ common/views/components/games/reversi/reversi.room.vue:
|
||||
this-game-is-started-soon: "The game will begin in seconds"
|
||||
waiting-for-other: "Waiting for the opponent"
|
||||
waiting-for-me: "Waiting for the your preparation"
|
||||
waiting-for-both: "Prepareing"
|
||||
waiting-for-both: "Preparing"
|
||||
cancel: "Cancel"
|
||||
ready: "Ready"
|
||||
cancel-ready: "Cancel \"Ready\""
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "Profile"
|
||||
notification: "Notification"
|
||||
apps: "Apps"
|
||||
mute: "Mute"
|
||||
mute-and-block: "Mute / Block"
|
||||
blocking: "Blocking"
|
||||
security: "Security"
|
||||
signin: "Sign in history"
|
||||
password: "Password"
|
||||
@ -847,28 +849,39 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "Settings saved!"
|
||||
failed: "Failed to setup. Please ensure that the token is correct."
|
||||
info: "From the next time you sign in to Misskey, the token displayed on your device will be necessary too, as well as the password."
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "To access the API, set this token as the key 'i' of request parameters."
|
||||
caution: "Do not enter this token to any apps nor tell this token to others otherwise your account may get compromised."
|
||||
regeneration-of-token: "If your token gets leaked, you can regenerate it."
|
||||
regenerate-token: "Regenerate the token"
|
||||
token: "Token:"
|
||||
enter-password: "Please enter the password"
|
||||
enter-password: "Enter the password"
|
||||
console:
|
||||
title: 'API console'
|
||||
endpoint: 'Endpoint'
|
||||
parameter: 'Parameters'
|
||||
send: 'Send'
|
||||
sending: 'Sending'
|
||||
response: 'Result'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "No linked applications"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "Max"
|
||||
in-use: "In use"
|
||||
stats: "Statistics"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "No muted users"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "Mute / Block"
|
||||
mute: "Mute"
|
||||
block: "Blocking"
|
||||
no-muted-users: "No muted users"
|
||||
no-blocked-users: "No blocked users"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "Change password"
|
||||
enter-current-password: "Enter the current password"
|
||||
enter-new-password: "Enter the new password"
|
||||
enter-new-password-again: "Enter new password again"
|
||||
enter-new-password-again: "Enter the new password again"
|
||||
not-match: "The new passwords do not match"
|
||||
changed: "Password updated"
|
||||
changed: "Password changed"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "This post is private"
|
||||
deleted: "This post has been deleted"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "Pop-out"
|
||||
close: "Close"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "Dashboard"
|
||||
instance: "Instance"
|
||||
emoji: "Emoji"
|
||||
users: "Users"
|
||||
update: "Updates"
|
||||
update: "Update"
|
||||
announcements: "Announcements"
|
||||
hashtags: "Hashtags"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Back to Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Dashboard"
|
||||
all-users: "All Users"
|
||||
original-users: "Users on this instance"
|
||||
all-notes: "All the posts"
|
||||
original-notes: "Posts on this instance"
|
||||
accounts: "Accounts"
|
||||
notes: "Notes"
|
||||
drive: "Drive"
|
||||
instances: "Instances"
|
||||
this-instance: "This instance"
|
||||
federated: "Federated"
|
||||
invite: "Invite"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "Chart"
|
||||
per-day: "per Day"
|
||||
per-hour: "per Hour"
|
||||
federation: "Federation"
|
||||
notes: "Posts"
|
||||
users: "Users"
|
||||
drive: "Drive"
|
||||
network: "Network"
|
||||
charts:
|
||||
federation-instances: "The number of instances: increase/decrease"
|
||||
federation-instances-total: "Total number of instances"
|
||||
notes: "The number of posts: increase/decrease (Combined)"
|
||||
local-notes: "The number of posts: increase/decrease (Local)"
|
||||
remote-notes: "The number of posts: increase/decrease (Remote)"
|
||||
notes-total: "Total posts"
|
||||
users: "The number of users: increase/decrease"
|
||||
users-total: "Total users"
|
||||
drive: "Capacity used as the storage: increase/decrease"
|
||||
drive-total: "Total usage of Drive"
|
||||
drive-files: "The number of files on the storage: increase/decrease"
|
||||
drive-files-total: "Total number of files on Drive"
|
||||
network-requests: "Requests"
|
||||
network-time: "Response time"
|
||||
network-usage: "Traffic"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "Suspend a user"
|
||||
suspend: "Suspend"
|
||||
suspended: "Successfully suspended."
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "Unsuspend users"
|
||||
unsuspend: "Unsuspend"
|
||||
unsuspended: "The user has successfully unsuspended."
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "User account verification settings"
|
||||
verify: "Verify account"
|
||||
verified: "The account is now being verified"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "User account unverification settings"
|
||||
unverify: "Unverify account"
|
||||
unverified: "The account is now being unverified"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "Add emoji"
|
||||
name: "Emoji name"
|
||||
name-desc: "You can use the characters a~z 0~9 _"
|
||||
aliases: "Aliases"
|
||||
aliases-desc: "You can add more than one, separated by spaces."
|
||||
url: "Image URL"
|
||||
add: "Add"
|
||||
emojis:
|
||||
title: "Emojis"
|
||||
update: "Update"
|
||||
remove: "Remove"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "Announcements"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "Save"
|
||||
remove: "Remove"
|
||||
add: "Add"
|
||||
title: "Title"
|
||||
text: "Content"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "Only media posts"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Mute"
|
||||
muted: "Muting"
|
||||
unmute: "Unmute"
|
||||
block: "Block"
|
||||
unblock: "Unblock"
|
||||
block-confirm: "Are you sure block this user?"
|
||||
push-to-a-list: "Add to list"
|
||||
list-pushed: "Successfully added {user} to {list}."
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "Sounds"
|
||||
enable-sounds: "Enable sounds"
|
||||
mark-as-read-all-unread-notes: "Mark all posts as read"
|
||||
password: "Password"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "Follows you"
|
||||
following: "Following"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "Timeline"
|
||||
media: "Media"
|
||||
is-suspended: "This account has been suspended."
|
||||
mute: "Mute"
|
||||
unmute: "Unmute"
|
||||
block: "Block"
|
||||
unblock: "Unblock"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "Recent notes"
|
||||
images: "Images"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "A la izqda."
|
||||
pop-right: "A la dcha."
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "¿Deseas <b>permitir</b> a <i>{{ app.name }}</i> acceder a tu cuenta?"
|
||||
permission-ask: "La aplicación requiere los siguientes permisos:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "Perfil"
|
||||
notification: "Notificación"
|
||||
apps: "Aplicaciones"
|
||||
mute: "Silenciar"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "Seguridad"
|
||||
signin: "Historial de inicios de sesión"
|
||||
password: "Contraseña"
|
||||
@ -847,28 +849,39 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "¡Configuraciones guardadas!"
|
||||
failed: "Error al configurar. Por favor asegúrate de que el token es correcto."
|
||||
info: "Desde ahora, ingresa el token que se muestra en tu dispositivo adicionalmente a tu contraseña cuando inicies sesión en Misskey"
|
||||
desktop/views/components/settings.api.vue:
|
||||
intro: "Para acceder al API, configura este token como la letra \"i\" de los parámetros requeridos."
|
||||
caution: "Por favor no muestres este token a otros (no lo ingreses en otro lugar que no sea aquí). De otra forma, tu cuenta puede llegar a ser comprometida."
|
||||
regeneration-of-token: "En el caso no deseado de que este token lo tenga otra persona, puedes regenerarlo."
|
||||
regenerate-token: "Regenerar el token"
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "Por favor ingresa tu contraseña"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "No hay aplicaciones asociadas"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "No hay usuarios silenciados"
|
||||
desktop/views/components/settings.password.vue:
|
||||
reset: "Cambiar contraseña"
|
||||
enter-current-password: "Ingresar contraseña actual"
|
||||
enter-new-password: "Ingresar nueva contraseña"
|
||||
enter-new-password-again: "Ingresar nueva contraseña de nuevo"
|
||||
not-match: "Las nuevas contraseñas no se corresponden consigo mismas"
|
||||
changed: "Contraseña actualizada"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
enter-new-password-again: "もう一度新しいパスワードを入力してください"
|
||||
not-match: "新しいパスワードが一致しません"
|
||||
changed: "パスワードを変更しました"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "この投稿は非公開です"
|
||||
deleted: "この投稿は削除されました"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
@ -28,11 +28,11 @@ common:
|
||||
BSoD:
|
||||
fatal-error: ":( 致命的な問題が発生しました。"
|
||||
update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。"
|
||||
error-code: "エラーコード"
|
||||
browser-version: "ブラウザ バージョン"
|
||||
client-version: "クライアント バージョン"
|
||||
error-code: "Code d’erreur"
|
||||
browser-version: "Version du navigateur"
|
||||
client-version: "La version du client"
|
||||
email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。"
|
||||
thanks: "Thank you for using Misskey."
|
||||
thanks: "Merci d’avoir choisi d’utiliser Misskey."
|
||||
got-it: "J'ai compris !"
|
||||
customization-tips:
|
||||
title: "Conseils de personnalisation"
|
||||
@ -62,7 +62,7 @@ common:
|
||||
years_ago: "Il y a {} an·s"
|
||||
month-and-day: "{month} mois/{day} jour"
|
||||
trash: "Corbeille"
|
||||
drive: "ドライブ"
|
||||
drive: "Drive"
|
||||
weekday-short:
|
||||
sunday: "D"
|
||||
monday: "L"
|
||||
@ -124,12 +124,12 @@ common:
|
||||
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
||||
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
||||
do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.'
|
||||
is-remote-user: "このユーザー情報はコピーです。"
|
||||
is-remote-user: "Ces informations utilisateur ont été copiées."
|
||||
is-remote-post: "この投稿情報はコピーです。"
|
||||
view-on-remote: "正確な情報を見る"
|
||||
view-on-remote: "Consulter le profil complet"
|
||||
error:
|
||||
title: '問題が発生しました'
|
||||
retry: 'やり直す'
|
||||
title: 'Une erreur est survenue'
|
||||
retry: 'Réessayer'
|
||||
reversi:
|
||||
drawn: "Partie nulle"
|
||||
my-turn: "C’est votre tour"
|
||||
@ -185,7 +185,8 @@ common:
|
||||
rename: "Renommer"
|
||||
stack-left: "Vers la gauche"
|
||||
pop-right: "Vers la droite"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
dev: "Échec lors de la création de l’application. Veuillez réessayer."
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "Désirez-vous <b>autoriser</b> <i>{{ app.name }}</i> à avoir accès à votre compte ?"
|
||||
permission-ask: "Cette application nécessite les autorisations suivantes :"
|
||||
@ -444,7 +445,7 @@ common/views/components/profile-editor.vue:
|
||||
is-cat: "Ce compte est un Chat"
|
||||
is-bot: "Ce compte est un Bot"
|
||||
is-locked: "Demandes d’abonnements requièrent l’approbation"
|
||||
careful-bot: "Botからのフォローだけ承認制にする"
|
||||
careful-bot: "Les demandes d’abonnements venant de Bots requièrent l’approbation"
|
||||
advanced: "Avancé"
|
||||
privacy: "Vie privée"
|
||||
save: "Mettre à jour le profil"
|
||||
@ -501,7 +502,7 @@ common/views/widgets/tips.vue:
|
||||
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
|
||||
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
|
||||
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
|
||||
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています"
|
||||
tips-line20: "Pourcentage sur le widget calendrier qui indique le pourcentage de temps passé"
|
||||
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
|
||||
tips-line23: "Mayu est mignone avec ses sourcils."
|
||||
tips-line24: "Misskey a vu le jour en 2014"
|
||||
@ -542,24 +543,24 @@ desktop/views/components/charts.vue:
|
||||
title: "Graphiques"
|
||||
per-day: "par jour"
|
||||
per-hour: "par heure"
|
||||
federation: "フェデレーション"
|
||||
federation: "Fédération"
|
||||
notes: "Publications"
|
||||
users: "Utilisateurs"
|
||||
drive: "Drive"
|
||||
network: "Réseau"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
federation-instances: "Nombre d’instances : augmentation/diminution"
|
||||
federation-instances-total: "Nombre total d’instances"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "Total des notes"
|
||||
users: "Nombre d’utilisateurs·trices : augmentation/diminution"
|
||||
users-total: "ユーザーの積算"
|
||||
users-total: "Nombre total des utilisateurs·rices"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-total: "Utilisation totale du lecteur"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
drive-files-total: "Nombre total de fichiers sur le lecteur"
|
||||
network-requests: "Requêtes"
|
||||
network-time: "Temps de réponse"
|
||||
network-usage: "Traffic"
|
||||
@ -679,10 +680,10 @@ desktop/views/components/note.vue:
|
||||
reposted-by: "Partagé par {}"
|
||||
reply: "Répondre"
|
||||
renote: "Partager"
|
||||
add-reaction: "リアクション"
|
||||
detail: "詳細"
|
||||
private: "この投稿は非公開です"
|
||||
deleted: "この投稿は削除されました"
|
||||
add-reaction: "Ajouter votre réaction"
|
||||
detail: "Détails"
|
||||
private: "Cette publication est privée"
|
||||
deleted: "Cette publication a été supprimée"
|
||||
desktop/views/components/notes.vue:
|
||||
error: "Échec du chargement."
|
||||
retry: "Réessayer"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "Profil"
|
||||
notification: "Notification"
|
||||
apps: "Applications"
|
||||
mute: "Mettre en sourdine"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "Sécurité"
|
||||
signin: "Historique de connexion"
|
||||
password: "Mot de Passe"
|
||||
@ -765,7 +767,7 @@ desktop/views/components/settings.vue:
|
||||
deck-default: "デッキをデフォルトのUIにする"
|
||||
display: "Affichage et design"
|
||||
customize: "Personnaliser l'Accueil"
|
||||
wallpaper: "壁紙"
|
||||
wallpaper: "Arrière plan"
|
||||
choose-wallpaper: "Sélectionner un fond d'écran"
|
||||
delete-wallpaper: "Supprimer le fond d'écran"
|
||||
dark-mode: "Mode nuit"
|
||||
@ -777,14 +779,14 @@ desktop/views/components/settings.vue:
|
||||
suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie"
|
||||
show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur"
|
||||
show-reply-target: "Afficher les réponses"
|
||||
timeline: "タイムライン"
|
||||
timeline: "Chronologie"
|
||||
show-my-renotes: "Afficher mes republications dans le fil"
|
||||
show-renoted-my-notes: "Afficher mes republications dans les fils"
|
||||
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
|
||||
show-local-renotes: "Afficher les partages locaux sur les fils"
|
||||
show-maps: "Afficher la carte"
|
||||
deck-column-align: "デッキのカラムの位置"
|
||||
deck-column-align-center: "中央"
|
||||
deck-column-align-left: "左"
|
||||
deck-column-align-center: "Centrer"
|
||||
deck-column-align-left: "À gauche"
|
||||
sound: "Son"
|
||||
enable-sounds: "Activer le son"
|
||||
enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur."
|
||||
@ -825,7 +827,7 @@ desktop/views/components/settings.vue:
|
||||
tools: "Outils"
|
||||
task-manager: "Gestionnaire de tâches"
|
||||
third-parties: "Services tiers"
|
||||
navbar-position: "ナビゲーションバーの位置"
|
||||
navbar-position: "Position de la barre de navigation"
|
||||
navbar-position-top: "En haut"
|
||||
navbar-position-left: "à gauche"
|
||||
navbar-position-right: "à droite"
|
||||
@ -847,27 +849,38 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "L'operation a été complétée avec succès!"
|
||||
failed: "L'operation a échoué. Veuillez vous assurer que le token a été entrer correctement."
|
||||
info: "À partir de maintenant, à chaque fois que vous vous connecter entrez votre mot de passe ainsi que le token généré sur votre appareil."
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "Si votre jeton est compromis, vous pouvez le régénérer."
|
||||
regenerate-token: "Regenerer le token"
|
||||
regenerate-token: "Régénérer le jeton"
|
||||
token: "Jeton :"
|
||||
enter-password: "Veuillez entrer le mot de passe"
|
||||
enter-password: "Entrez le mot de passe"
|
||||
console:
|
||||
title: 'Console API'
|
||||
endpoint: 'Point de terminaison'
|
||||
parameter: 'Paramètres'
|
||||
send: 'Envoyer'
|
||||
sending: 'Envoi en cours'
|
||||
response: 'Résultat'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "Aucune application autorisée"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "Aucun utilisateurs mis en sourdine"
|
||||
desktop/views/components/settings.password.vue:
|
||||
reset: "Changer votre mot de passe"
|
||||
max: "Maximale"
|
||||
in-use: "utilisé"
|
||||
stats: "Statistiques"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "Silencer / Bloquer"
|
||||
mute: "Mettre en sourdine"
|
||||
block: "En cours blocage"
|
||||
no-muted-users: "Aucun utilisateur·rice n’est mis·e en sourdine"
|
||||
no-blocked-users: "Aucun utilisateur·rice n’est bloqué·e"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "Modifier le mot de passe"
|
||||
enter-current-password: "Entrez votre mot de passe actuel"
|
||||
enter-new-password: "Entrez votre nouveau mot de passe"
|
||||
enter-new-password: "Saisissez le nouveau mot de passe"
|
||||
enter-new-password-again: "Entrez à nouveau le nouveau mot de passe"
|
||||
not-match: "Le nouveau mot de passe ne correspond pas."
|
||||
not-match: "Les nouveaux mots de passe ne sont pas identiques"
|
||||
changed: "Mot de passe modifié avec succès"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "cette publication est privée"
|
||||
@ -934,55 +947,100 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "Fermer"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "Tableau de bord"
|
||||
instance: "Instance"
|
||||
emoji: "Emoji"
|
||||
users: "Utilisateur·rice·s"
|
||||
update: "Mises à jour"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
update: "Mise à jour"
|
||||
announcements: "Annonces"
|
||||
hashtags: "Hashtags"
|
||||
back-to-misskey: "Retour vers Misskey"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "Tableau de bord"
|
||||
all-users: "Toutes les utilisateurrices"
|
||||
original-users: "Utilisateur·rice·s sur cette instance"
|
||||
all-notes: "Toutes les publications"
|
||||
original-notes: "Publications sur cette instance"
|
||||
invite: "Invitation"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
accounts: "Comptes"
|
||||
notes: "Notes"
|
||||
drive: "Lecteur"
|
||||
instances: "Instances"
|
||||
this-instance: "Cette instance"
|
||||
federated: "Fédérées"
|
||||
invite: "Inviter"
|
||||
banner-url: "URL de la bannière"
|
||||
disableRegistration: "Désactiver l’enregistrement de nouveaux utilisateur·rice·s"
|
||||
disableLocalTimeline: "Désactiver le fil local"
|
||||
admin/views/charts.vue:
|
||||
title: "Graph"
|
||||
per-day: "par jour"
|
||||
per-hour: "par heure"
|
||||
federation: "Fédération"
|
||||
notes: "Publications"
|
||||
users: "Utilisateur·rice·s"
|
||||
drive: "Lecteur"
|
||||
network: "Réseau"
|
||||
charts:
|
||||
federation-instances: "Nombre d’instances : augmentation/diminution"
|
||||
federation-instances-total: "Nombre total d’instances"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "Total des publications"
|
||||
users: "Nombre d’utilisateur·rice·s : augmentation/diminution"
|
||||
users-total: "Nombre total des utilisateur·rice·s"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "Utilisation totale du lecteur"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "Nombre total de fichiers sur le lecteur"
|
||||
network-requests: "Requêtes"
|
||||
network-time: "Temps de réponse"
|
||||
network-usage: "Traffic"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "Suspendre un·e utilisateur·rice"
|
||||
suspend: "Suspendre"
|
||||
suspended: "Suspendu avec succès"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
suspended: "Suspendu·e avec succès."
|
||||
unsuspend-user: "Lever la suspension d’utilisateur·rice·s"
|
||||
unsuspend: "Suspension levée"
|
||||
unsuspended: "La suspension de l’utilisateur·rice a été levée avec succès"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "Paramètres de vérification du compte utilisateur"
|
||||
verify: "Vérification du compte"
|
||||
verified: "Le compte a été vérifié"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "Ôter la vérification du compte"
|
||||
unverified: "Ce compte n'est pas vérifié"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
unverified: "Ce compte n'est plus vérifié"
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "Ajouter un émoji"
|
||||
name: "Nom de l’émoji"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "Aliases"
|
||||
aliases-desc: "Vous pouvez définir plus d’un, séparés par des espaces."
|
||||
url: "URL de l’image"
|
||||
add: "Ajouter"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "Annonces"
|
||||
save: "Enregistrer"
|
||||
remove: "Supprimer"
|
||||
add: "Ajouter"
|
||||
title: "Titre"
|
||||
text: "Contenu"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Tags cachés"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "Les publications médias uniquement"
|
||||
is-media-view: "Vue média"
|
||||
edit: "Options"
|
||||
desktop/views/pages/deck/deck.user-column.vue:
|
||||
posts: "投稿"
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
images: "画像"
|
||||
activity: "アクティビティ"
|
||||
timeline: "タイムライン"
|
||||
pinned-notes: "ピン留めされた投稿"
|
||||
push-to-a-list: "リストに追加"
|
||||
posts: "Publications"
|
||||
following: "Suit"
|
||||
followers: "Abonné·e·s"
|
||||
images: "Images"
|
||||
activity: "Activité"
|
||||
timeline: "Chronologie"
|
||||
pinned-notes: "Publications épinglées"
|
||||
push-to-a-list: "Ajouter à la liste"
|
||||
desktop/views/pages/stats/stats.vue:
|
||||
all-users: "Toutes les utilisateurrices"
|
||||
original-users: "Utilisateur·rice·s sur cette instance"
|
||||
@ -1035,7 +1093,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
no-users: "Pas d'utilisateurs"
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "Ce compte a été suspendu."
|
||||
last-used-at: "最終アクセス"
|
||||
last-used-at: "Actif·ive pour la dernière fois"
|
||||
desktop/views/pages/user/user.photos.vue:
|
||||
title: "Photos"
|
||||
loading: "Chargement en cours"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Mettre en sourdine"
|
||||
muted: "Muting"
|
||||
unmute: "Enlever la sourdine"
|
||||
block: "Bloquer"
|
||||
unblock: "Débloquer"
|
||||
block-confirm: "Bloquer cet utilisateur ?"
|
||||
push-to-a-list: "Ajouter à la liste"
|
||||
list-pushed: "Vous avez ajouté {user} à la liste {list}."
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1055,10 +1116,10 @@ desktop/views/pages/user/user.header.vue:
|
||||
following: "Suit"
|
||||
followers: "Abonné·e·s"
|
||||
is-bot: "Ce compte est un Bot"
|
||||
years-old: "歳"
|
||||
year: "年"
|
||||
month: "月"
|
||||
day: "日"
|
||||
years-old: "ans d’âge"
|
||||
year: "Année"
|
||||
month: "Mois"
|
||||
day: "Jour"
|
||||
desktop/views/pages/user/user.timeline.vue:
|
||||
default: "Publications"
|
||||
with-replies: "Publications et réponses"
|
||||
@ -1117,8 +1178,8 @@ mobile/views/components/drive.file-detail.vue:
|
||||
hash: "Hash (md5)"
|
||||
exif: "EXIF"
|
||||
nsfw: "CW"
|
||||
mark-as-sensitive: "閲覧注意に設定"
|
||||
unmark-as-sensitive: "閲覧注意を解除"
|
||||
mark-as-sensitive: "Marquer comme sensible"
|
||||
unmark-as-sensitive: "Ne pas marquer comme sensible"
|
||||
mobile/views/components/media-image.vue:
|
||||
sensitive: "Le contenu est NSFW"
|
||||
click-to-show: "Cliquer pour afficher"
|
||||
@ -1278,8 +1339,8 @@ mobile/views/pages/settings.vue:
|
||||
timeline: "Fil d'actualité"
|
||||
show-reply-target: "Afficher les réponses"
|
||||
show-my-renotes: "Afficher mes republications"
|
||||
show-renoted-my-notes: "自分の投稿のRenoteを表示する"
|
||||
show-local-renotes: "ローカルの投稿のRenoteを表示する"
|
||||
show-renoted-my-notes: "Afficher mes publications partagées"
|
||||
show-local-renotes: "Afficher les publications partagées localement"
|
||||
post-style: "Style de la publication"
|
||||
post-style-standard: "Standard"
|
||||
post-style-smart: "Intelligent"
|
||||
@ -1312,7 +1373,8 @@ mobile/views/pages/settings.vue:
|
||||
signout: "Déconnexion"
|
||||
sound: "Sons"
|
||||
enable-sounds: "Activer les sons"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues"
|
||||
password: "Mot de Passe"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "Vous suit"
|
||||
following: "Abonnements"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "Fil d'actualité"
|
||||
media: "Media"
|
||||
is-suspended: "This account has been suspended."
|
||||
mute: "Mettre en sourdine"
|
||||
unmute: "Enlever la sourdine"
|
||||
block: "Bloquer"
|
||||
unblock: "Débloquer"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "Notes récentes"
|
||||
images: "Images"
|
||||
@ -1368,28 +1434,28 @@ docs:
|
||||
dev/views/index.vue:
|
||||
manage-apps: "Gestion des applications"
|
||||
dev/views/apps.vue:
|
||||
manage-apps: "アプリを管理"
|
||||
create-app: "アプリ作成"
|
||||
app-missing: "アプリなし"
|
||||
manage-apps: "Gestion des applications"
|
||||
create-app: "Créer une app"
|
||||
app-missing: "Aucune application"
|
||||
dev/views/new-app.vue:
|
||||
create-app: "アプリケーションの作成"
|
||||
app-name: "アプリケーション名"
|
||||
app-name-desc: "あなたのアプリの名称。"
|
||||
app-name-ex: "ex) Misskey for iOS"
|
||||
app-overview: "アプリの概要"
|
||||
app-desc: "あなたのアプリの簡単な説明や紹介。"
|
||||
app-desc-ex: "ex) Misskey iOSクライアント。"
|
||||
create-app: "Création d’une application"
|
||||
app-name: "Nom de l’application"
|
||||
app-name-desc: "Le nom de votre application"
|
||||
app-name-ex: "p. ex. Misskey pour iOS"
|
||||
app-overview: "Description courte de l’application"
|
||||
app-desc: "Brève description introductive à votre application."
|
||||
app-desc-ex: "p. ex) Misskey pour iOS"
|
||||
callback-url: "コールバックURL (オプション)"
|
||||
callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。"
|
||||
authority: "権限"
|
||||
authority: "Autorisations "
|
||||
authority-desc: "ここで要求した機能だけがAPIからアクセスできます。"
|
||||
authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。"
|
||||
account-read: "アカウントの情報を見る。"
|
||||
account-write: "アカウントの情報を操作する。"
|
||||
note-write: "投稿する。"
|
||||
reaction-write: "リアクションしたりリアクションをキャンセルする。"
|
||||
following-write: "フォローしたりフォロー解除する。"
|
||||
drive-read: "ドライブを見る。"
|
||||
drive-write: "ドライブを操作する。"
|
||||
notification-read: "通知を見る。"
|
||||
notification-write: "通知を操作する。"
|
||||
account-read: "Afficher les informations du compte"
|
||||
account-write: "Modifications des informations du compte"
|
||||
note-write: "Publications."
|
||||
reaction-write: "Ajout et suppression de réactions."
|
||||
following-write: "S’abonner et se désabonner."
|
||||
drive-read: "Lecture du Drive."
|
||||
drive-write: "Téléversement/suppression des fichiers de votre Lecteur."
|
||||
notification-read: "Lire vos notifications."
|
||||
notification-write: "Gestion de vos notifications."
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
@ -201,6 +201,7 @@ common:
|
||||
pop-right: "右に出す"
|
||||
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
@ -416,6 +417,7 @@ common/views/components/signin.vue:
|
||||
signin: "サインイン"
|
||||
or: "または"
|
||||
signin-with-twitter: "Twitterでログイン"
|
||||
signin-with-github: "GitHubでログイン"
|
||||
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
|
||||
|
||||
common/views/components/signup.vue:
|
||||
@ -459,6 +461,14 @@ common/views/components/twitter-setting.vue:
|
||||
connect: "Twitterと接続する"
|
||||
disconnect: "切断する"
|
||||
|
||||
common/views/components/github-setting.vue:
|
||||
description: "お使いのGitHubアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでGitHubアカウント情報が表示されるようになったり、GitHubを用いた便利なサインインを利用できるようになります。"
|
||||
connected-to: "次のGitHubアカウントに接続されています"
|
||||
detail: "詳細..."
|
||||
reconnect: "再接続する"
|
||||
connect: "GitHubと接続する"
|
||||
disconnect: "切断する"
|
||||
|
||||
common/views/components/uploader.vue:
|
||||
waiting: "待機中"
|
||||
|
||||
@ -598,32 +608,6 @@ desktop/views/components/calendar.vue:
|
||||
next: "次の月"
|
||||
go: "クリックして時間遡行"
|
||||
|
||||
desktop/views/components/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
|
||||
desktop/views/components/choose-file-from-drive-window.vue:
|
||||
choose-file: "ファイル選択中"
|
||||
upload: "PCからドライブにファイルをアップロード"
|
||||
@ -832,7 +816,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -950,13 +935,20 @@ desktop/views/components/settings.2fa.vue:
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
@ -966,10 +958,14 @@ common/views/components/drive-settings.vue:
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -1057,48 +1053,98 @@ desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/instance.vue:
|
||||
instance: "インスタンス"
|
||||
instance-name: "インスタンス名"
|
||||
instance-description: "インスタンスの紹介"
|
||||
banner-url: "バナー画像URL"
|
||||
disableRegistration: "ユーザー登録の受付を停止する"
|
||||
disableLocalTimeline: "ローカルタイムラインを無効にする"
|
||||
invite: "招待"
|
||||
save: "保存"
|
||||
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
@ -1116,12 +1162,6 @@ desktop/views/pages/deck/deck.user-column.vue:
|
||||
pinned-notes: "ピン留めされた投稿"
|
||||
push-to-a-list: "リストに追加"
|
||||
|
||||
desktop/views/pages/stats/stats.vue:
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
|
||||
desktop/views/pages/welcome.vue:
|
||||
about: "詳しく..."
|
||||
gotit: "わかった"
|
||||
@ -1196,6 +1236,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
|
||||
@ -1500,6 +1543,10 @@ mobile/views/pages/settings.vue:
|
||||
twitter-connect: "Twitterアカウントに接続する"
|
||||
twitter-reconnect: "再接続する"
|
||||
twitter-disconnect: "切断する"
|
||||
github: "GitHub連携"
|
||||
github-connect: "GitHubアカウントに接続する"
|
||||
github-reconnect: "再接続する"
|
||||
github-disconnect: "切断する"
|
||||
update: "Misskey Update"
|
||||
version: "バージョン:"
|
||||
latest-version: "最新のバージョン:"
|
||||
@ -1514,6 +1561,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
@ -1524,6 +1572,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねんで!"
|
||||
pop-right: "右に出すで!"
|
||||
dev: "アプリの作成あかんかったわ。もっぺんやってみて。"
|
||||
ai-chan-kawaii: "藍ちゃめっさべっぴんさんや"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があんさんのアカウントにアクセスすんのを<b>許可</b>してもええか?"
|
||||
permission-ask: "このアプリは次の権限を要求してんで:"
|
||||
@ -741,8 +742,9 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
security: "守護神セキュリティ"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "こんな感じでサインインしたらしいで"
|
||||
password: "パスワード"
|
||||
2fa: "二段階認証"
|
||||
@ -847,26 +849,37 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了したで!"
|
||||
failed: "なんか設定に失敗したで。トークンを間違えとらんか確認してや。"
|
||||
info: "次のサインインからは、パスワードに加えてデバイスに出とるトークンを入力してな。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」っちゅうキーでパラメータに付加してリクエストしてや。"
|
||||
caution: "アカウントを不正利用されるかも知れんから、このトークンは第三者に教えたらあかんで(アプリなどにも入力しんといてな)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたとかその可能性があったらトークンを再生成できるで。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "トークン:"
|
||||
enter-password: "パスワードを入力してや"
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "API使うんやったらこのトークンを「i」っちゅうパラメータにくっつけてリクエストできるで。"
|
||||
caution: "アカウント勝手にいじられるかも知れんから、このトークンは教えたらあかんし、アプリにも書いたらあかんで(これはフリちゃうで)"
|
||||
regeneration-of-token: "トークン漏れてもうたんやったらもっかい生成できるで。"
|
||||
regenerate-token: "トークンもっかい生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入れてや"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送る'
|
||||
sending: '応答待っとる'
|
||||
response: 'こんなん返ってきたわ'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはあらへんで"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
in-use: "使うとる"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはおらんで"
|
||||
desktop/views/components/settings.password.vue:
|
||||
reset: "パスワードを変更する"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしとるユーザーはおらんで"
|
||||
no-blocked-users: "ブロックしとるユーザーはおらんで"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワード変える"
|
||||
enter-current-password: "今のパスワードを入れてや"
|
||||
enter-new-password: "さらのパスワード入れてや"
|
||||
enter-new-password-again: "もういっぺんさらのパスワードを入れてや"
|
||||
enter-new-password: "こんどのパスワード入れてや"
|
||||
enter-new-password-again: "もっぺん入れてや"
|
||||
not-match: "パスワードがおうとらん"
|
||||
changed: "パスワード変えたわ"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "さいなら"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
announcements: "知っといてや"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "知り合い全員や"
|
||||
original-users: "ここの人らだけ"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "ワイのインスタンス"
|
||||
federated: "連合"
|
||||
invite: "来てや"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減(統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結したで"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
suspended: "凍結しました"
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除したで"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
unsuspended: "凍結を解除しました"
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしたで"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウントにせーへん"
|
||||
unverify: "公式アカウントにはさせへんで"
|
||||
unverified: "公式アカウントを解除したで"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
verified: "公式アカウントにしました"
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿だけや"
|
||||
@ -979,10 +1037,10 @@ desktop/views/pages/deck/deck.user-column.vue:
|
||||
following: "フォロー"
|
||||
followers: "フォロワー"
|
||||
images: "画像"
|
||||
activity: "アクティビティ"
|
||||
activity: "やっとること"
|
||||
timeline: "タイムライン"
|
||||
pinned-notes: "ピン留めされた投稿"
|
||||
push-to-a-list: "リストに追加"
|
||||
pinned-notes: "ピン留めしはった投稿"
|
||||
push-to-a-list: "リストに入れたる"
|
||||
desktop/views/pages/stats/stats.vue:
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "ここの人らだけ"
|
||||
@ -1035,7 +1093,7 @@ desktop/views/pages/user/user.friends.vue:
|
||||
no-users: "よう話すツレは居らん"
|
||||
desktop/views/pages/user/user.vue:
|
||||
is-suspended: "このユーザーはあかんわ。凍結されとる。"
|
||||
last-used-at: "最終アクセス"
|
||||
last-used-at: "最後いつ来はった?"
|
||||
desktop/views/pages/user/user.photos.vue:
|
||||
title: "写真"
|
||||
loading: "読み込んどります"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしとるで"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加したで。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1117,8 +1178,8 @@ mobile/views/components/drive.file-detail.vue:
|
||||
hash: "ハッシュ(md5)"
|
||||
exif: "EXIF"
|
||||
nsfw: "ちょっと見せられへんわ"
|
||||
mark-as-sensitive: "閲覧注意に設定"
|
||||
unmark-as-sensitive: "閲覧注意を解除"
|
||||
mark-as-sensitive: "見たらあかん感じにしとく"
|
||||
unmark-as-sensitive: "やっぱ見せたるわ"
|
||||
mobile/views/components/media-image.vue:
|
||||
sensitive: "見たらあかんで"
|
||||
click-to-show: "押してみ、見せたるわ"
|
||||
@ -1312,7 +1373,8 @@ mobile/views/pages/settings.vue:
|
||||
signout: "さいなら"
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンド鳴らす"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
mark-as-read-all-unread-notes: "全部もう読んだわ"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされとるで"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーはあかんわ。凍結されとる。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロックやめたる"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近儲かりまっか?"
|
||||
images: "画像"
|
||||
@ -1369,27 +1435,27 @@ dev/views/index.vue:
|
||||
manage-apps: "アプリの管理"
|
||||
dev/views/apps.vue:
|
||||
manage-apps: "アプリを管理"
|
||||
create-app: "アプリ作成"
|
||||
app-missing: "アプリなし"
|
||||
create-app: "アプリ作る"
|
||||
app-missing: "アプリあらへん"
|
||||
dev/views/new-app.vue:
|
||||
create-app: "アプリケーションの作成"
|
||||
app-name: "アプリケーション名"
|
||||
app-name-desc: "あなたのアプリの名称。"
|
||||
app-name-ex: "ex) Misskey for iOS"
|
||||
app-overview: "アプリの概要"
|
||||
app-desc: "あなたのアプリの簡単な説明や紹介。"
|
||||
app-desc-ex: "ex) Misskey iOSクライアント。"
|
||||
callback-url: "コールバックURL (オプション)"
|
||||
callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。"
|
||||
create-app: "アプリケーション作る"
|
||||
app-name: "アプリケーションの名前"
|
||||
app-name-desc: "あんたのアプリの名前。"
|
||||
app-name-ex: "ex) 関西ミスキー保安協会"
|
||||
app-overview: "このアプリどんなん?"
|
||||
app-desc: "あんたのアプリどんなんか教えて"
|
||||
app-desc-ex: "ex) 関西人なら誰でも口ずさめるこのCMがついにMisskeyへ。"
|
||||
callback-url: "コールバックURL (無くてもええで)"
|
||||
callback-url-desc: "ユーザーが認証フォームで認証した後どこに連れてくかを設定できるで"
|
||||
authority: "権限"
|
||||
authority-desc: "ここで要求した機能だけがAPIからアクセスできます。"
|
||||
authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。"
|
||||
account-read: "アカウントの情報を見る。"
|
||||
account-write: "アカウントの情報を操作する。"
|
||||
note-write: "投稿する。"
|
||||
reaction-write: "リアクションしたりリアクションをキャンセルする。"
|
||||
following-write: "フォローしたりフォロー解除する。"
|
||||
drive-read: "ドライブを見る。"
|
||||
drive-write: "ドライブを操作する。"
|
||||
notification-read: "通知を見る。"
|
||||
notification-write: "通知を操作する。"
|
||||
authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな"
|
||||
authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。"
|
||||
account-read: "アカウントの情報見せて"
|
||||
account-write: "アカウントの情報いじらせて"
|
||||
note-write: "投稿させて"
|
||||
reaction-write: "リアクションしたりそれをキャンセルさせて"
|
||||
following-write: "フォローとかフォロー解除させて"
|
||||
drive-read: "ドライブ見せて"
|
||||
drive-write: "ドライブいじらせて"
|
||||
notification-read: "通知見せて"
|
||||
notification-write: "通知いじらせて"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "Profiel"
|
||||
notification: "Melding"
|
||||
apps: "Apps"
|
||||
mute: "Dempen"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "Beveiliging"
|
||||
signin: "Inloggeschiedenis"
|
||||
password: "Wachtwoord"
|
||||
@ -847,28 +849,39 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "Instellen voltooid!"
|
||||
failed: "Instellen mislukt. Zorg ervoor dat de sleutel juist is."
|
||||
info: "Vanaf nu moet je ook de op je apparaat getoonde sleutel tonen bij het inloggen op Misskey."
|
||||
desktop/views/components/settings.api.vue:
|
||||
intro: "Als je toegang wilt tot de API, stel deze sleutel dan in als 'i' bij de verzoekparameters."
|
||||
caution: "Laat deze sleutel niet zien aan derde partijen (en voer hem nergens anders in dan hier), anders kan je account gehackt worden."
|
||||
regeneration-of-token: "Mocht deze sleutel tóch uitlekken, dan kun je hem opnieuw genereren."
|
||||
regenerate-token: "Sleutel opnieuw genereren"
|
||||
token: "Sleutel:"
|
||||
enter-password: "Voer je wachtwoord in"
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "Geen gedempte gebruikers"
|
||||
desktop/views/components/settings.password.vue:
|
||||
reset: "Wachtwoord wijzigen"
|
||||
enter-current-password: "Voer je huidige wachtwoord in"
|
||||
enter-new-password: "Voer je nieuwe wachtwoord in"
|
||||
enter-new-password-again: "Voer je nieuwe wachtwoord nogmaals in"
|
||||
not-match: "Het nieuwe wachtwoord komt niet overeen"
|
||||
changed: "Wachtwoord bijgewerkt"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
enter-new-password-again: "もう一度新しいパスワードを入力してください"
|
||||
not-match: "新しいパスワードが一致しません"
|
||||
changed: "パスワードを変更しました"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "この投稿は非公開です"
|
||||
deleted: "この投稿は削除されました"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "Uitvouwen"
|
||||
close: "Sluiten"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Dempen"
|
||||
muted: "Dempend"
|
||||
unmute: "Ontdempen"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "Volgt jou"
|
||||
following: "Volgend"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "Tijdlijn"
|
||||
media: "Media"
|
||||
is-suspended: "Dit account is geschorst."
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "Recente notities"
|
||||
images: "Afbeeldingen"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "Til høyre"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "Notifikasjon"
|
||||
apps: "Apper"
|
||||
mute: "Demp"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "Passord"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "Lukk"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
users: "Brukere"
|
||||
update: "Oppdater"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
invite: "Inviter"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "Suspender"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "Lyder"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "Følger"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "Media"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "Nylige innlegg"
|
||||
images: "Bilder"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "Przypnij do lewej"
|
||||
pop-right: "Odepnij w prawo"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "Czy chcesz <b>zezwolić</b> <i>{{ app.name }}</i> na dostęp do Twojego konta?"
|
||||
permission-ask: "Ta aplikacja wymaga następujących uprawnień:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "Profil"
|
||||
notification: "Powiadomienia"
|
||||
apps: "Aplikacje"
|
||||
mute: "Wyciszanie"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "Bezpieczeństwo"
|
||||
signin: "Historia logowań"
|
||||
password: "Hasło"
|
||||
@ -847,28 +849,39 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "Pomyślnie ukończono konfigurację!"
|
||||
failed: "Nie udało się skonfigurować uwierzytelniania dwuetapowego, upewnij się że wprowadziłeś prawidłowy token."
|
||||
info: "Od teraz, wprowadzaj token wyświetlany na urządzeniu przy każdym logowaniu do Misskey."
|
||||
desktop/views/components/settings.api.vue:
|
||||
intro: "Aby uzyskać dostęp do API, ustaw ten token jako klucz 'i' parametrów żądań."
|
||||
caution: "Nie pokazuj tego tokenu osobom trzecim (nie wprowadzaj go nigdzie indziej), aby konto nie trafiło w niepowołane ręce."
|
||||
regeneration-of-token: "W przypadku wycieku tokenu, możesz wygenerować nowy."
|
||||
regenerate-token: "Wygeneruj nowy token"
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "Wprowadź hasło"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "Brak zautoryzowanych aplikacji"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "Brak wyciszonych użytkowników"
|
||||
desktop/views/components/settings.password.vue:
|
||||
reset: "Zmień hasło"
|
||||
enter-current-password: "Wprowadź obecne hasło"
|
||||
enter-new-password: "Wprowadź nowe hasło"
|
||||
enter-new-password-again: "Wprowadź ponownie nowe hasło"
|
||||
not-match: "Nowe hasła nie pasują do siebie"
|
||||
changed: "Pomyślnie zmieniono hasło"
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
enter-new-password-again: "もう一度新しいパスワードを入力してください"
|
||||
not-match: "新しいパスワードが一致しません"
|
||||
changed: "パスワードを変更しました"
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "ten wpis jest prywatny"
|
||||
deleted: "ten wpis został usunięty"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "Pop-out"
|
||||
close: "Zamknij"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "Tylko wpisy z zawartością multimedialną"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "Wycisz"
|
||||
muted: "Wyciszyłeś"
|
||||
unmute: "Cofnij wyciszenie"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "Dodaj do listy"
|
||||
list-pushed: "Dodałeś(-aś) {user} do {list}."
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "Śledzi Cię"
|
||||
following: "Śledzeni"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "Oś czasu"
|
||||
media: "Multimedia"
|
||||
is-suspended: "To konto zostało zablokowane"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "Ostatnie wpisy"
|
||||
images: "Zdjęcia"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "Acoplar à direita"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "Você <b>permite</b> que <i>{{ app.name }}</i> acesse sua conta?"
|
||||
permission-ask: "Este aplicativo precisa das seguintes permissões:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
users: "Usuários"
|
||||
update: "Actualizações"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "Todos os usuários"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "Sons"
|
||||
enable-sounds: "Ativar sons"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "Te segue"
|
||||
following: "Seguindo"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "Linha do tempo"
|
||||
media: "Mídia"
|
||||
is-suspended: "Esta conta foi suspensa"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "Notas recentes"
|
||||
images: "Imagens"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
@ -186,6 +186,7 @@ common:
|
||||
stack-left: "左に重ねる"
|
||||
pop-right: "右に出す"
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
auth/views/form.vue:
|
||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
||||
permission-ask: "このアプリは次の権限を要求しています:"
|
||||
@ -741,7 +742,8 @@ desktop/views/components/settings.vue:
|
||||
profile: "プロフィール"
|
||||
notification: "通知"
|
||||
apps: "アプリ"
|
||||
mute: "ミュート"
|
||||
mute-and-block: "ミュート/ブロック"
|
||||
blocking: "ブロック"
|
||||
security: "セキュリティ"
|
||||
signin: "サインイン履歴"
|
||||
password: "パスワード"
|
||||
@ -847,22 +849,33 @@ desktop/views/components/settings.2fa.vue:
|
||||
success: "設定が完了しました!"
|
||||
failed: "設定に失敗しました。トークンに誤りがないかご確認ください。"
|
||||
info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。"
|
||||
desktop/views/components/settings.api.vue:
|
||||
common/views/components/api-settings.vue:
|
||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||
regenerate-token: "トークンを再生成"
|
||||
token: "Token:"
|
||||
enter-password: "パスワードを入力してください"
|
||||
console:
|
||||
title: 'APIコンソール'
|
||||
endpoint: 'エンドポイント'
|
||||
parameter: 'パラメータ'
|
||||
send: '送信'
|
||||
sending: '応答待ち'
|
||||
response: '結果'
|
||||
desktop/views/components/settings.apps.vue:
|
||||
no-apps: "連携しているアプリケーションはありません"
|
||||
common/views/components/drive-settings.vue:
|
||||
max: "容量"
|
||||
in-use: "使用中"
|
||||
stats: "統計"
|
||||
desktop/views/components/settings.mute.vue:
|
||||
no-users: "ミュートしているユーザーはいません"
|
||||
desktop/views/components/settings.password.vue:
|
||||
common/views/components/mute-and-block.vue:
|
||||
mute-and-block: "ミュートとブロック"
|
||||
mute: "ミュート"
|
||||
block: "ブロック"
|
||||
no-muted-users: "ミュートしているユーザーはいません"
|
||||
no-blocked-users: "ブロックしているユーザーはいません"
|
||||
common/views/components/password-settings.vue:
|
||||
reset: "パスワードを変更する"
|
||||
enter-current-password: "現在のパスワードを入力してください"
|
||||
enter-new-password: "新しいパスワードを入力してください"
|
||||
@ -934,41 +947,86 @@ desktop/views/components/users-list-item.vue:
|
||||
desktop/views/components/window.vue:
|
||||
popout: "ポップアウト"
|
||||
close: "閉じる"
|
||||
desktop/views/pages/admin/admin.vue:
|
||||
admin/views/index.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
instance: "インスタンス"
|
||||
emoji: "カスタム絵文字"
|
||||
users: "ユーザー"
|
||||
update: "更新"
|
||||
announcements: "お知らせ"
|
||||
hashtags: "ハッシュタグ"
|
||||
desktop/views/pages/admin/admin.dashboard.vue:
|
||||
back-to-misskey: "Misskeyに戻る"
|
||||
admin/views/dashboard.vue:
|
||||
dashboard: "ダッシュボード"
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
all-notes: "全ての投稿"
|
||||
original-notes: "このインスタンスの投稿"
|
||||
accounts: "アカウント"
|
||||
notes: "投稿"
|
||||
drive: "ドライブ"
|
||||
instances: "インスタンス"
|
||||
this-instance: "このインスタンス"
|
||||
federated: "連合"
|
||||
invite: "招待"
|
||||
banner-url: "Banner URL"
|
||||
disableRegistration: "Disable new user registration"
|
||||
disableLocalTimeline: "Disable the local timeline"
|
||||
desktop/views/pages/admin/admin.suspend-user.vue:
|
||||
admin/views/charts.vue:
|
||||
title: "チャート"
|
||||
per-day: "1日ごと"
|
||||
per-hour: "1時間ごと"
|
||||
federation: "フェデレーション"
|
||||
notes: "投稿"
|
||||
users: "ユーザー"
|
||||
drive: "ドライブ"
|
||||
network: "ネットワーク"
|
||||
charts:
|
||||
federation-instances: "インスタンスの増減"
|
||||
federation-instances-total: "インスタンスの積算"
|
||||
notes: "投稿の増減 (統合)"
|
||||
local-notes: "投稿の増減 (ローカル)"
|
||||
remote-notes: "投稿の増減 (リモート)"
|
||||
notes-total: "投稿の積算"
|
||||
users: "ユーザーの増減"
|
||||
users-total: "ユーザーの積算"
|
||||
drive: "ドライブ使用量の増減"
|
||||
drive-total: "ドライブ使用量の積算"
|
||||
drive-files: "ドライブのファイル数の増減"
|
||||
drive-files-total: "ドライブのファイル数の積算"
|
||||
network-requests: "リクエスト"
|
||||
network-time: "応答時間"
|
||||
network-usage: "通信量"
|
||||
admin/views/users.vue:
|
||||
suspend-user: "ユーザーの凍結"
|
||||
suspend: "凍結"
|
||||
suspended: "凍結しました"
|
||||
desktop/views/pages/admin/admin.unsuspend-user.vue:
|
||||
unsuspend-user: "ユーザーの凍結の解除"
|
||||
unsuspend: "凍結の解除"
|
||||
unsuspended: "凍結を解除しました"
|
||||
desktop/views/pages/admin/admin.verify-user.vue:
|
||||
verify-user: "ユーザーの公式アカウント設定"
|
||||
verify: "公式アカウントにする"
|
||||
verified: "公式アカウントにしました"
|
||||
desktop/views/pages/admin/admin.unverify-user.vue:
|
||||
unverify-user: "ユーザーの公式アカウント解除"
|
||||
unverify: "公式アカウントを解除する"
|
||||
unverified: "公式アカウントを解除しました"
|
||||
desktop/views/pages/admin/admin.announcements.vue:
|
||||
admin/views/emoji.vue:
|
||||
add-emoji:
|
||||
title: "絵文字の登録"
|
||||
name: "絵文字名"
|
||||
name-desc: "a~z 0~9 _ の文字が使えます。"
|
||||
aliases: "エイリアス"
|
||||
aliases-desc: "スペースで区切って複数設定できます。"
|
||||
url: "絵文字画像URL"
|
||||
add: "追加"
|
||||
emojis:
|
||||
title: "絵文字一覧"
|
||||
update: "更新"
|
||||
remove: "削除"
|
||||
admin/views/announcements.vue:
|
||||
announcements: "お知らせ"
|
||||
desktop/views/pages/admin/admin.hashtags.vue:
|
||||
save: "保存"
|
||||
remove: "削除"
|
||||
add: "追加"
|
||||
title: "タイトル"
|
||||
text: "内容"
|
||||
admin/views/hashtags.vue:
|
||||
hided-tags: "Hidden Tags"
|
||||
desktop/views/pages/deck/deck.tl-column.vue:
|
||||
is-media-only: "メディア投稿のみ"
|
||||
@ -1048,6 +1106,9 @@ desktop/views/pages/user/user.profile.vue:
|
||||
mute: "ミュートする"
|
||||
muted: "ミュートしています"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロックする"
|
||||
unblock: "ブロック解除"
|
||||
block-confirm: "このユーザーをブロックしますか?"
|
||||
push-to-a-list: "リストに追加"
|
||||
list-pushed: "{user}を{list}に追加しました。"
|
||||
desktop/views/pages/user/user.header.vue:
|
||||
@ -1313,6 +1374,7 @@ mobile/views/pages/settings.vue:
|
||||
sound: "サウンド"
|
||||
enable-sounds: "サウンドを有効にする"
|
||||
mark-as-read-all-unread-notes: "すべての投稿を既読にする"
|
||||
password: "パスワード"
|
||||
mobile/views/pages/user.vue:
|
||||
follows-you: "フォローされています"
|
||||
following: "フォロー"
|
||||
@ -1322,6 +1384,10 @@ mobile/views/pages/user.vue:
|
||||
timeline: "タイムライン"
|
||||
media: "メディア"
|
||||
is-suspended: "このユーザーは凍結されています。"
|
||||
mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
mobile/views/pages/user/home.vue:
|
||||
recent-notes: "最近の投稿"
|
||||
images: "画像"
|
||||
|
17340
package-lock.json
generated
17340
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "10.32.0",
|
||||
"clientVersion": "1.0.11138",
|
||||
"version": "10.38.5",
|
||||
"clientVersion": "1.0.11513",
|
||||
"codename": "nighthike",
|
||||
"main": "./built/index.js",
|
||||
"private": true,
|
||||
@ -58,23 +58,24 @@
|
||||
"@types/koa__cors": "2.2.3",
|
||||
"@types/minio": "7.0.0",
|
||||
"@types/mkdirp": "0.5.2",
|
||||
"@types/mocha": "5.2.3",
|
||||
"@types/mocha": "5.2.5",
|
||||
"@types/mongodb": "3.1.12",
|
||||
"@types/ms": "0.7.30",
|
||||
"@types/node": "10.12.0",
|
||||
"@types/node": "10.12.2",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/portscanner": "2.1.0",
|
||||
"@types/pug": "2.0.4",
|
||||
"@types/qrcode": "1.3.0",
|
||||
"@types/ratelimiter": "2.1.28",
|
||||
"@types/redis": "2.8.7",
|
||||
"@types/request": "2.47.1",
|
||||
"@types/request": "2.48.0",
|
||||
"@types/request-promise-native": "1.0.15",
|
||||
"@types/rimraf": "2.0.2",
|
||||
"@types/seedrandom": "2.4.27",
|
||||
"@types/sharp": "0.21.0",
|
||||
"@types/showdown": "1.7.5",
|
||||
"@types/single-line-log": "1.1.0",
|
||||
"@types/speakeasy": "2.0.2",
|
||||
"@types/speakeasy": "2.0.3",
|
||||
"@types/systeminformation": "3.23.0",
|
||||
"@types/tinycolor2": "1.4.1",
|
||||
"@types/tmp": "0.0.33",
|
||||
@ -84,35 +85,34 @@
|
||||
"@types/websocket": "0.0.40",
|
||||
"@types/ws": "6.0.1",
|
||||
"animejs": "2.2.0",
|
||||
"apexcharts": "2.1.5",
|
||||
"apexcharts": "2.1.9",
|
||||
"autobind-decorator": "2.1.0",
|
||||
"autosize": "4.0.2",
|
||||
"autwh": "0.1.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bee-queue": "1.2.2",
|
||||
"bootstrap-vue": "2.0.0-rc.11",
|
||||
"cafy": "11.3.0",
|
||||
"cafy": "12.0.0",
|
||||
"chai": "4.2.0",
|
||||
"chai-http": "4.2.0",
|
||||
"chalk": "2.4.1",
|
||||
"chart.js": "2.7.3",
|
||||
"commander": "2.19.0",
|
||||
"crc-32": "1.2.0",
|
||||
"css-loader": "1.0.0",
|
||||
"css-loader": "1.0.1",
|
||||
"dateformat": "3.0.3",
|
||||
"debug": "4.1.0",
|
||||
"deep-equal": "1.0.1",
|
||||
"deepcopy": "0.6.3",
|
||||
"diskusage": "0.2.5",
|
||||
"double-ended-queue": "2.1.0-0",
|
||||
"elasticsearch": "15.1.1",
|
||||
"elasticsearch": "15.2.0",
|
||||
"emojilib": "2.3.0",
|
||||
"escape-regexp": "0.0.1",
|
||||
"eslint": "5.7.0",
|
||||
"eslint": "5.8.0",
|
||||
"eslint-plugin-vue": "4.7.1",
|
||||
"eventemitter3": "3.1.0",
|
||||
"file-loader": "2.0.0",
|
||||
"file-type": "10.1.0",
|
||||
"file-type": "10.3.0",
|
||||
"fuckadblock": "3.2.1",
|
||||
"gulp": "3.9.1",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
@ -129,13 +129,13 @@
|
||||
"gulp-uglify": "3.0.1",
|
||||
"gulp-util": "3.0.8",
|
||||
"hard-source-webpack-plugin": "0.12.0",
|
||||
"html-minifier": "3.5.20",
|
||||
"html-minifier": "3.5.21",
|
||||
"http-signature": "1.2.0",
|
||||
"insert-text-at-cursor": "0.1.1",
|
||||
"is-root": "2.0.0",
|
||||
"is-url": "1.2.4",
|
||||
"js-yaml": "3.12.0",
|
||||
"jsdom": "12.2.0",
|
||||
"jsdom": "13.0.0",
|
||||
"json5": "2.1.0",
|
||||
"json5-loader": "1.0.1",
|
||||
"koa": "2.6.1",
|
||||
@ -201,17 +201,16 @@
|
||||
"textarea-caret": "3.1.0",
|
||||
"tinycolor2": "1.4.1",
|
||||
"tmp": "0.0.33",
|
||||
"ts-loader": "5.2.2",
|
||||
"ts-loader": "5.3.0",
|
||||
"ts-node": "7.0.1",
|
||||
"tslint": "5.10.0",
|
||||
"typescript": "3.1.3",
|
||||
"typescript-eslint-parser": "20.0.0",
|
||||
"typescript": "3.1.5",
|
||||
"typescript-eslint-parser": "20.1.1",
|
||||
"uglify-es": "3.3.9",
|
||||
"url-loader": "1.1.2",
|
||||
"uuid": "3.3.2",
|
||||
"v-animate-css": "0.0.2",
|
||||
"vue": "2.5.17",
|
||||
"vue-chartjs": "3.4.0",
|
||||
"vue-color": "2.7.0",
|
||||
"vue-content-loading": "1.5.3",
|
||||
"vue-cropperjs": "2.2.2",
|
||||
@ -229,17 +228,10 @@
|
||||
"vuex-persistedstate": "2.5.4",
|
||||
"web-push": "3.3.3",
|
||||
"webfinger.js": "2.6.6",
|
||||
"webpack": "4.23.0",
|
||||
"webpack": "4.23.1",
|
||||
"webpack-cli": "3.1.2",
|
||||
"websocket": "1.0.28",
|
||||
"ws": "6.1.0",
|
||||
"xev": "2.0.1"
|
||||
},
|
||||
"greenkeeper": {
|
||||
"ignore": [
|
||||
"deepcopy",
|
||||
"cafy",
|
||||
"@types/gulp"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ export default abstract class Chart<T> {
|
||||
null;
|
||||
|
||||
// ログ取得
|
||||
const logs = await this.collection.find({
|
||||
let logs = await this.collection.find({
|
||||
group: group,
|
||||
span: span,
|
||||
date: {
|
||||
@ -245,6 +245,27 @@ export default abstract class Chart<T> {
|
||||
}
|
||||
});
|
||||
|
||||
// 要求された範囲にログがひとつもなかったら
|
||||
if (logs.length == 0) {
|
||||
// もっとも新しいログを持ってくる
|
||||
// (すくなくともひとつログが無いと隙間埋めできないため)
|
||||
const recentLog = await this.collection.findOne({
|
||||
group: group,
|
||||
span: span
|
||||
}, {
|
||||
sort: {
|
||||
date: -1
|
||||
},
|
||||
fields: {
|
||||
_id: 0
|
||||
}
|
||||
});
|
||||
|
||||
if (recentLog) {
|
||||
logs = [recentLog];
|
||||
}
|
||||
}
|
||||
|
||||
// 整形
|
||||
for (let i = (range - 1); i >= 0; i--) {
|
||||
const current =
|
||||
@ -269,14 +290,11 @@ export default abstract class Chart<T> {
|
||||
|
||||
/**
|
||||
* [{
|
||||
* xxxxx: 1,
|
||||
* yyyyy: 5
|
||||
* xxxxx: 1, yyyyy: 5
|
||||
* }, {
|
||||
* xxxxx: 2,
|
||||
* yyyyy: 6
|
||||
* xxxxx: 2, yyyyy: 6
|
||||
* }, {
|
||||
* xxxxx: 3,
|
||||
* yyyyy: 7
|
||||
* xxxxx: 3, yyyyy: 7
|
||||
* }]
|
||||
*
|
||||
* を
|
||||
|
150
src/client/app/admin/assets/header-icon.svg
Normal file
150
src/client/app/admin/assets/header-icon.svg
Normal file
@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 135.46667 135.46667"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="header-icon.dark.svg"
|
||||
inkscape:export-filename="C:\Users\syuilo\projects\misskey\assets\favicon\32.png"
|
||||
inkscape:export-xdpi="6"
|
||||
inkscape:export-ydpi="6">
|
||||
<defs
|
||||
id="defs2">
|
||||
<inkscape:path-effect
|
||||
effect="simplify"
|
||||
id="path-effect5115"
|
||||
is_visible="true"
|
||||
steps="1"
|
||||
threshold="0.000408163"
|
||||
smooth_angles="360"
|
||||
helper_size="0"
|
||||
simplify_individual_paths="false"
|
||||
simplify_just_coalesce="false"
|
||||
simplifyindividualpaths="false"
|
||||
simplifyJustCoalesce="false" />
|
||||
<inkscape:path-effect
|
||||
effect="simplify"
|
||||
id="path-effect5111"
|
||||
is_visible="true"
|
||||
steps="1"
|
||||
threshold="0.000408163"
|
||||
smooth_angles="360"
|
||||
helper_size="0"
|
||||
simplify_individual_paths="false"
|
||||
simplify_just_coalesce="false"
|
||||
simplifyindividualpaths="false"
|
||||
simplifyJustCoalesce="false" />
|
||||
<inkscape:path-effect
|
||||
effect="simplify"
|
||||
id="path-effect5104"
|
||||
is_visible="true"
|
||||
steps="1"
|
||||
threshold="0.000408163"
|
||||
smooth_angles="360"
|
||||
helper_size="0"
|
||||
simplify_individual_paths="false"
|
||||
simplify_just_coalesce="false"
|
||||
simplifyindividualpaths="false"
|
||||
simplifyJustCoalesce="false" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:cx="114.309"
|
||||
inkscape:cy="251.50613"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g4502"
|
||||
showgrid="true"
|
||||
units="px"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="false"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1027"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="1072"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
objecttolerance="1"
|
||||
guidetolerance="1"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:snap-others="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4504"
|
||||
spacingx="4.2333334"
|
||||
spacingy="4.2333334"
|
||||
empcolor="#ff3fff"
|
||||
empopacity="0.25098039"
|
||||
empspacing="4" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="レイヤー 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-30.809093,-111.78601)">
|
||||
<g
|
||||
id="g4502"
|
||||
transform="matrix(1.096096,0,0,1.096096,-2.960633,-44.023579)">
|
||||
<g
|
||||
style="fill-opacity:1"
|
||||
transform="translate(-1.3333333e-6,-1.3439941e-6)"
|
||||
id="g5125">
|
||||
<g
|
||||
transform="matrix(0.91391326,0,0,0.91391326,7.9719907,17.595761)"
|
||||
id="text4489"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.03404236px;line-height:476.69509888px;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';letter-spacing:0px;word-spacing:0px;fill-opacity:1;stroke:none;stroke-width:0.28950602px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
aria-label="Mi">
|
||||
<path
|
||||
sodipodi:nodetypes="zccssscssccscczzzccsccsscscsccz"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5210"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill-opacity:1;stroke-width:0.28950602px"
|
||||
d="m 75.196381,231.17126 c -5.855419,0.0202 -10.885068,-3.50766 -13.2572,-7.61584 -1.266603,-1.79454 -3.772419,-2.43291 -3.807919,0 v 11.2332 c 0,4.51309 -1.645397,8.41504 -4.936191,11.70583 -3.196772,3.19677 -7.098714,4.79516 -11.705826,4.79516 -4.513089,0 -8.415031,-1.59839 -11.705825,-4.79516 -3.196772,-3.29079 -4.795158,-7.19274 -4.795158,-11.70583 v -61.7729 c 0,-3.47884 0.987238,-6.6286 2.961715,-9.44928 2.068499,-2.91471 4.701135,-4.9362 7.897906,-6.06447 1.786431,-0.65816 3.666885,-0.98724 5.641362,-0.98724 5.077225,0 9.308247,1.97448 12.693064,5.92343 1.786431,1.97448 2.820681,3.00873 3.102749,3.10275 0,0 13.408119,16.21319 13.78421,16.49526 0.376091,0.28206 1.480789,2.43848 4.127113,2.43848 2.646324,0 3.89218,-2.15642 4.26827,-2.43848 0.376091,-0.28207 13.784088,-16.49526 13.784088,-16.49526 0.09402,0.094 1.081261,-0.94022 2.961715,-3.10275 3.478837,-3.94895 7.756866,-5.92343 12.834096,-5.92343 1.88045,0 3.76091,0.32908 5.64136,0.98724 3.19677,1.12827 5.7824,3.14976 7.75688,6.06447 2.06849,2.82068 3.10274,5.97044 3.10274,9.44928 v 61.7729 c 0,4.51309 -1.6454,8.41504 -4.93619,11.70583 -3.19677,3.19677 -7.09871,4.79516 -11.70582,4.79516 -4.51309,0 -8.41504,-1.59839 -11.705828,-4.79516 -3.196772,-3.29079 -4.795158,-7.19274 -4.795158,-11.70583 v -11.2332 c -0.277898,-3.06563 -2.987588,-1.13379 -3.948953,0 -2.538613,4.70114 -7.401781,7.59567 -13.2572,7.61584 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5212"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'OTADESIGN Rounded';-inkscape-font-specification:'OTADESIGN Rounded';fill-opacity:1;stroke-width:0.28950602px"
|
||||
d="m 145.83461,185.00361 q -5.92343,0 -10.15445,-4.08999 -4.08999,-4.23102 -4.08999,-10.15445 0,-5.92343 4.08999,-10.01342 4.23102,-4.23102 10.15445,-4.23102 5.92343,0 10.15445,4.23102 4.23102,4.08999 4.23102,10.01342 0,5.92343 -4.23102,10.15445 -4.23102,4.08999 -10.15445,4.08999 z m 0.14103,2.82068 q 5.92343,0 10.01342,4.23102 4.23102,4.23102 4.23102,10.15445 v 34.83541 q 0,5.92343 -4.23102,10.15445 -4.08999,4.08999 -10.01342,4.08999 -5.92343,0 -10.15445,-4.08999 -4.23102,-4.23102 -4.23102,-10.15445 v -34.83541 q 0,-5.92343 4.23102,-10.15445 4.23102,-4.23102 10.15445,-4.23102 z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.0 KiB |
27
src/client/app/admin/script.ts
Normal file
27
src/client/app/admin/script.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Admin
|
||||
*/
|
||||
|
||||
import VueRouter from 'vue-router';
|
||||
|
||||
// Style
|
||||
import './style.styl';
|
||||
|
||||
import init from '../init';
|
||||
import Index from './views/index.vue';
|
||||
|
||||
init(launch => {
|
||||
document.title = 'Admin';
|
||||
|
||||
// Init router
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: '/admin/',
|
||||
routes: [
|
||||
{ path: '/', component: Index },
|
||||
]
|
||||
});
|
||||
|
||||
// Launch the app
|
||||
launch(router);
|
||||
});
|
6
src/client/app/admin/style.styl
Normal file
6
src/client/app/admin/style.styl
Normal file
@ -0,0 +1,6 @@
|
||||
@import "../app"
|
||||
@import "../reset"
|
||||
|
||||
html
|
||||
height 100%
|
||||
background var(--bg)
|
71
src/client/app/admin/views/announcements.vue
Normal file
71
src/client/app/admin/views/announcements.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
|
||||
<ui-card>
|
||||
<div slot="title">%fa:broadcast-tower% %i18n:@announcements%</div>
|
||||
<section v-for="(announcement, i) in announcements" class="fit-top">
|
||||
<ui-input v-model="announcement.title" @change="save">
|
||||
<span>%i18n:@title%</span>
|
||||
</ui-input>
|
||||
<ui-textarea v-model="announcement.text">
|
||||
<span>%i18n:@text%</span>
|
||||
</ui-textarea>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="save">%fa:save R% %i18n:@save%</ui-button>
|
||||
<ui-button @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button>
|
||||
</ui-horizon-group>
|
||||
</section>
|
||||
<section>
|
||||
<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
announcements: [],
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.announcements = meta.broadcasts;
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
add() {
|
||||
this.announcements.push({
|
||||
title: '',
|
||||
text: ''
|
||||
});
|
||||
},
|
||||
|
||||
remove(i) {
|
||||
this.announcements = this.announcements.filter((_, j) => j !== i);
|
||||
this.save();
|
||||
},
|
||||
|
||||
save() {
|
||||
(this as any).api('admin/update-meta', {
|
||||
broadcasts: this.announcements
|
||||
}).then(() => {
|
||||
//(this as any).os.apis.dialog({ text: `Saved` });
|
||||
}).catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.cdeuzmsthagexbkpofbmatmugjuvogfb
|
||||
@media (min-width 500px)
|
||||
padding 16px
|
||||
|
||||
</style>
|
105
src/client/app/admin/views/ap-log.vue
Normal file
105
src/client/app/admin/views/ap-log.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="hyhctythnmwihguaaapnbrbszsjqxpio">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>%fa:exchange-alt% In/Out</th>
|
||||
<th>%fa:server% Host</th>
|
||||
<th>%fa:bolt% Activity</th>
|
||||
<th>%fa:user% Actor</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="log in logs" :key="log.id">
|
||||
<td :class="log.direction">{{ log.direction == 'in' ? '<' : '>' }} {{ log.direction }}</td>
|
||||
<td>{{ log.host }}</td>
|
||||
<td>{{ log.activity }}</td>
|
||||
<td>@{{ log.actor }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
logs: [],
|
||||
connection: null
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = (this as any).os.stream.useSharedConnection('apLog');
|
||||
this.connection.on('log', this.onLog);
|
||||
this.connection.on('logs', this.onLogs);
|
||||
this.connection.send('requestLog', {
|
||||
id: Math.random().toString().substr(2, 8),
|
||||
length: 50
|
||||
});
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.dispose();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onLog(log) {
|
||||
log.id = Math.random();
|
||||
this.logs.unshift(log);
|
||||
if (this.logs.length > 50) this.logs.pop();
|
||||
},
|
||||
|
||||
onLogs(logs) {
|
||||
logs.reverse().forEach(log => this.onLog(log));
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.hyhctythnmwihguaaapnbrbszsjqxpio
|
||||
display block
|
||||
padding 12px 16px 16px 16px
|
||||
height 250px
|
||||
overflow hidden
|
||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||
background var(--adminDashboardCardBg)
|
||||
border-radius 8px
|
||||
|
||||
> table
|
||||
width 100%
|
||||
max-width 100%
|
||||
overflow auto
|
||||
border-spacing 0
|
||||
border-collapse collapse
|
||||
color var(--adminDashboardCardFg)
|
||||
font-size 14px
|
||||
|
||||
thead
|
||||
border-bottom solid 1px var(--adminDashboardCardDivider)
|
||||
|
||||
tr
|
||||
th
|
||||
font-weight normal
|
||||
text-align left
|
||||
|
||||
tbody
|
||||
tr
|
||||
&:nth-child(odd)
|
||||
background rgba(0, 0, 0, 0.025)
|
||||
|
||||
th, td
|
||||
padding 8px 16px
|
||||
min-width 128px
|
||||
|
||||
td.in
|
||||
color #d26755
|
||||
|
||||
td.out
|
||||
color #55bb83
|
||||
|
||||
</style>
|
469
src/client/app/admin/views/charts.vue
Normal file
469
src/client/app/admin/views/charts.vue
Normal file
@ -0,0 +1,469 @@
|
||||
<template>
|
||||
<div class="qvgidhudpqhjttdhxubzuyrhyzgslujw">
|
||||
<header>
|
||||
<b>%fa:chart-bar R% %i18n:@title%:</b>
|
||||
<select v-model="src">
|
||||
<optgroup label="%i18n:@federation%">
|
||||
<option value="federation-instances">%i18n:@charts.federation-instances%</option>
|
||||
<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@users%">
|
||||
<option value="users">%i18n:@charts.users%</option>
|
||||
<option value="users-total">%i18n:@charts.users-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@notes%">
|
||||
<option value="notes">%i18n:@charts.notes%</option>
|
||||
<option value="local-notes">%i18n:@charts.local-notes%</option>
|
||||
<option value="remote-notes">%i18n:@charts.remote-notes%</option>
|
||||
<option value="notes-total">%i18n:@charts.notes-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@drive%">
|
||||
<option value="drive-files">%i18n:@charts.drive-files%</option>
|
||||
<option value="drive-files-total">%i18n:@charts.drive-files-total%</option>
|
||||
<option value="drive">%i18n:@charts.drive%</option>
|
||||
<option value="drive-total">%i18n:@charts.drive-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@network%">
|
||||
<option value="network-requests">%i18n:@charts.network-requests%</option>
|
||||
<option value="network-time">%i18n:@charts.network-time%</option>
|
||||
<option value="network-usage">%i18n:@charts.network-usage%</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<div>
|
||||
<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span>
|
||||
</div>
|
||||
</header>
|
||||
<div ref="chart"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as tinycolor from 'tinycolor2';
|
||||
import * as ApexCharts from 'apexcharts';
|
||||
|
||||
const limit = 90;
|
||||
|
||||
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
|
||||
const negate = arr => arr.map(x => -x);
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
src: 'notes',
|
||||
span: 'hour',
|
||||
chartInstance: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
data(): any {
|
||||
if (this.chart == null) return null;
|
||||
switch (this.src) {
|
||||
case 'federation-instances': return this.federationInstancesChart(false);
|
||||
case 'federation-instances-total': return this.federationInstancesChart(true);
|
||||
case 'users': return this.usersChart(false);
|
||||
case 'users-total': return this.usersChart(true);
|
||||
case 'notes': return this.notesChart('combined');
|
||||
case 'local-notes': return this.notesChart('local');
|
||||
case 'remote-notes': return this.notesChart('remote');
|
||||
case 'notes-total': return this.notesTotalChart();
|
||||
case 'drive': return this.driveChart();
|
||||
case 'drive-total': return this.driveTotalChart();
|
||||
case 'drive-files': return this.driveFilesChart();
|
||||
case 'drive-files-total': return this.driveFilesTotalChart();
|
||||
case 'network-requests': return this.networkRequestsChart();
|
||||
case 'network-time': return this.networkTimeChart();
|
||||
case 'network-usage': return this.networkUsageChart();
|
||||
}
|
||||
},
|
||||
|
||||
stats(): any[] {
|
||||
const stats =
|
||||
this.span == 'day' ? this.chart.perDay :
|
||||
this.span == 'hour' ? this.chart.perHour :
|
||||
null;
|
||||
|
||||
return stats;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
src() {
|
||||
this.render();
|
||||
},
|
||||
|
||||
span() {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
this.now = new Date();
|
||||
|
||||
const [perHour, perDay] = await Promise.all([Promise.all([
|
||||
(this as any).api('charts/federation', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/users', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/notes', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/drive', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/network', { limit: limit, span: 'hour' })
|
||||
]), Promise.all([
|
||||
(this as any).api('charts/federation', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/users', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/notes', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/drive', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/network', { limit: limit, span: 'day' })
|
||||
])]);
|
||||
|
||||
const chart = {
|
||||
perHour: {
|
||||
federation: perHour[0],
|
||||
users: perHour[1],
|
||||
notes: perHour[2],
|
||||
drive: perHour[3],
|
||||
network: perHour[4]
|
||||
},
|
||||
perDay: {
|
||||
federation: perDay[0],
|
||||
users: perDay[1],
|
||||
notes: perDay[2],
|
||||
drive: perDay[3],
|
||||
network: perDay[4]
|
||||
}
|
||||
};
|
||||
|
||||
this.chart = chart;
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
methods: {
|
||||
setSrc(src) {
|
||||
this.src = src;
|
||||
},
|
||||
|
||||
render() {
|
||||
if (this.chartInstance) {
|
||||
this.chartInstance.destroy();
|
||||
}
|
||||
|
||||
this.chartInstance = new ApexCharts(this.$refs.chart, {
|
||||
chart: {
|
||||
type: 'area',
|
||||
height: 300,
|
||||
animations: {
|
||||
dynamicAnimation: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
grid: {
|
||||
clipMarkers: false,
|
||||
borderColor: 'rgba(0, 0, 0, 0.1)'
|
||||
},
|
||||
stroke: {
|
||||
curve: 'straight',
|
||||
width: 2
|
||||
},
|
||||
legend: {
|
||||
labels: {
|
||||
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'datetime',
|
||||
labels: {
|
||||
style: {
|
||||
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
|
||||
}
|
||||
},
|
||||
axisBorder: {
|
||||
color: 'rgba(0, 0, 0, 0.1)'
|
||||
},
|
||||
axisTicks: {
|
||||
color: 'rgba(0, 0, 0, 0.1)'
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: this.data.bytes ? v => Vue.filter('bytes')(v, 0) : v => Vue.filter('number')(v),
|
||||
style: {
|
||||
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
|
||||
}
|
||||
}
|
||||
},
|
||||
series: this.data.series
|
||||
});
|
||||
|
||||
this.chartInstance.render();
|
||||
},
|
||||
|
||||
getDate(i: number) {
|
||||
const y = this.now.getFullYear();
|
||||
const m = this.now.getMonth();
|
||||
const d = this.now.getDate();
|
||||
const h = this.now.getHours();
|
||||
|
||||
return (
|
||||
this.span == 'day' ? new Date(y, m, d - i) :
|
||||
this.span == 'hour' ? new Date(y, m, d, h - i) :
|
||||
null
|
||||
);
|
||||
},
|
||||
|
||||
format(arr) {
|
||||
return arr.map((v, i) => ({ x: this.getDate(i).getTime(), y: v }));
|
||||
},
|
||||
|
||||
federationInstancesChart(total: boolean): any {
|
||||
return {
|
||||
series: [{
|
||||
data: this.format(total
|
||||
? this.stats.federation.instance.total
|
||||
: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec))
|
||||
)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
notesChart(type: string): any {
|
||||
return {
|
||||
series: [{
|
||||
name: 'All',
|
||||
type: 'line',
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec))
|
||||
: sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec))
|
||||
)
|
||||
}, {
|
||||
name: 'Renotes',
|
||||
type: 'area',
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote)
|
||||
: this.stats.notes[type].diffs.renote
|
||||
)
|
||||
}, {
|
||||
name: 'Replies',
|
||||
type: 'area',
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply)
|
||||
: this.stats.notes[type].diffs.reply
|
||||
)
|
||||
}, {
|
||||
name: 'Normal',
|
||||
type: 'area',
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal)
|
||||
: this.stats.notes[type].diffs.normal
|
||||
)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
notesTotalChart(): any {
|
||||
return {
|
||||
series: [{
|
||||
name: 'Combined',
|
||||
data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total))
|
||||
}, {
|
||||
name: 'Local',
|
||||
data: this.format(this.stats.notes.local.total)
|
||||
}, {
|
||||
name: 'Remote',
|
||||
data: this.format(this.stats.notes.remote.total)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
usersChart(total: boolean): any {
|
||||
return {
|
||||
series: [{
|
||||
name: 'Combined',
|
||||
data: this.format(total
|
||||
? sum(this.stats.users.local.total, this.stats.users.remote.total)
|
||||
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
|
||||
)
|
||||
}, {
|
||||
name: 'Local',
|
||||
data: this.format(total
|
||||
? this.stats.users.local.total
|
||||
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec))
|
||||
)
|
||||
}, {
|
||||
name: 'Remote',
|
||||
data: this.format(total
|
||||
? this.stats.users.remote.total
|
||||
: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
|
||||
)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
driveChart(): any {
|
||||
return {
|
||||
bytes: true,
|
||||
series: [{
|
||||
name: 'All',
|
||||
data: this.format(
|
||||
sum(
|
||||
this.stats.drive.local.incSize,
|
||||
negate(this.stats.drive.local.decSize),
|
||||
this.stats.drive.remote.incSize,
|
||||
negate(this.stats.drive.remote.decSize)
|
||||
)
|
||||
)
|
||||
}, {
|
||||
name: 'Local +',
|
||||
data: this.format(this.stats.drive.local.incSize)
|
||||
}, {
|
||||
name: 'Local -',
|
||||
data: this.format(negate(this.stats.drive.local.decSize))
|
||||
}, {
|
||||
name: 'Remote +',
|
||||
data: this.format(this.stats.drive.remote.incSize)
|
||||
}, {
|
||||
name: 'Remote -',
|
||||
data: this.format(negate(this.stats.drive.remote.decSize))
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
driveTotalChart(): any {
|
||||
return {
|
||||
bytes: true,
|
||||
series: [{
|
||||
name: 'Combined',
|
||||
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
|
||||
}, {
|
||||
name: 'Local',
|
||||
data: this.format(this.stats.drive.local.totalSize)
|
||||
}, {
|
||||
name: 'Remote',
|
||||
data: this.format(this.stats.drive.remote.totalSize)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
driveFilesChart(): any {
|
||||
return {
|
||||
series: [{
|
||||
name: 'All',
|
||||
data: this.format(
|
||||
sum(
|
||||
this.stats.drive.local.incCount,
|
||||
negate(this.stats.drive.local.decCount),
|
||||
this.stats.drive.remote.incCount,
|
||||
negate(this.stats.drive.remote.decCount)
|
||||
)
|
||||
)
|
||||
}, {
|
||||
name: 'Local +',
|
||||
data: this.format(this.stats.drive.local.incCount)
|
||||
}, {
|
||||
name: 'Local -',
|
||||
data: this.format(negate(this.stats.drive.local.decCount))
|
||||
}, {
|
||||
name: 'Remote +',
|
||||
data: this.format(this.stats.drive.remote.incCount)
|
||||
}, {
|
||||
name: 'Remote -',
|
||||
data: this.format(negate(this.stats.drive.remote.decCount))
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
driveFilesTotalChart(): any {
|
||||
return {
|
||||
series: [{
|
||||
name: 'Combined',
|
||||
data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount))
|
||||
}, {
|
||||
name: 'Local',
|
||||
data: this.format(this.stats.drive.local.totalCount)
|
||||
}, {
|
||||
name: 'Remote',
|
||||
data: this.format(this.stats.drive.remote.totalCount)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
networkRequestsChart(): any {
|
||||
return {
|
||||
series: [{
|
||||
name: 'Incoming',
|
||||
data: this.format(this.stats.network.incomingRequests)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
networkTimeChart(): any {
|
||||
const data = [];
|
||||
|
||||
for (let i = 0; i < limit; i++) {
|
||||
data.push(this.stats.network.incomingRequests[i] != 0 ? (this.stats.network.totalTime[i] / this.stats.network.incomingRequests[i]) : 0);
|
||||
}
|
||||
|
||||
return {
|
||||
series: [{
|
||||
name: 'Avg time',
|
||||
data: this.format(data)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
networkUsageChart(): any {
|
||||
return {
|
||||
bytes: true,
|
||||
series: [{
|
||||
name: 'Incoming',
|
||||
data: this.format(this.stats.network.incomingBytes)
|
||||
}, {
|
||||
name: 'Outgoing',
|
||||
data: this.format(this.stats.network.outgoingBytes)
|
||||
}]
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.qvgidhudpqhjttdhxubzuyrhyzgslujw
|
||||
display block
|
||||
flex 1
|
||||
padding 32px 24px
|
||||
padding-bottom 0
|
||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||
background var(--face)
|
||||
border-radius 8px
|
||||
|
||||
> header
|
||||
display flex
|
||||
margin 0 8px
|
||||
padding 0 0 8px 0
|
||||
font-size 1em
|
||||
color var(--adminDashboardCardFg)
|
||||
border-bottom solid 1px var(--adminDashboardCardDivider)
|
||||
|
||||
> b
|
||||
margin-right 8px
|
||||
|
||||
> *:last-child
|
||||
margin-left auto
|
||||
|
||||
*
|
||||
&:not(.active)
|
||||
color var(--primary)
|
||||
cursor pointer
|
||||
|
||||
</style>
|
180
src/client/app/admin/views/cpu-memory.vue
Normal file
180
src/client/app/admin/views/cpu-memory.vue
Normal file
@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div class="zyknedwtlthezamcjlolyusmipqmjgxz">
|
||||
<div>
|
||||
<header>
|
||||
<span>%fa:microchip% CPU <span>{{ cpuP }}%</span></span>
|
||||
<span v-if="meta">{{ meta.cpu.model }}</span>
|
||||
</header>
|
||||
<div ref="cpu"></div>
|
||||
</div>
|
||||
<div>
|
||||
<header>
|
||||
<span>%fa:memory% MEM <span>{{ memP }}%</span></span>
|
||||
<span v-if="meta"></span>
|
||||
</header>
|
||||
<div ref="mem"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as ApexCharts from 'apexcharts';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['connection'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
stats: [],
|
||||
cpuChart: null,
|
||||
memChart: null,
|
||||
cpuP: '',
|
||||
memP: '',
|
||||
meta: null
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
stats(stats) {
|
||||
this.cpuChart.updateSeries([{
|
||||
data: stats.map((x, i) => ({ x: i, y: x.cpu_usage }))
|
||||
}]);
|
||||
this.memChart.updateSeries([{
|
||||
data: stats.map((x, i) => ({ x: i, y: (x.mem.used / x.mem.total) }))
|
||||
}]);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.meta = meta;
|
||||
});
|
||||
|
||||
this.connection.on('stats', this.onStats);
|
||||
this.connection.on('statsLog', this.onStatsLog);
|
||||
this.connection.send('requestLog', {
|
||||
id: Math.random().toString().substr(2, 8),
|
||||
length: 200
|
||||
});
|
||||
|
||||
const chartOpts = {
|
||||
chart: {
|
||||
type: 'area',
|
||||
height: 200,
|
||||
animations: {
|
||||
dynamicAnimation: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
toolbar: {
|
||||
show: false
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
grid: {
|
||||
clipMarkers: false,
|
||||
borderColor: 'rgba(0, 0, 0, 0.1)'
|
||||
},
|
||||
stroke: {
|
||||
curve: 'straight',
|
||||
width: 2
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
series: [{
|
||||
data: []
|
||||
}],
|
||||
xaxis: {
|
||||
type: 'numeric',
|
||||
labels: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
show: false,
|
||||
min: 0,
|
||||
max: 1
|
||||
}
|
||||
};
|
||||
|
||||
this.cpuChart = new ApexCharts(this.$refs.cpu, chartOpts);
|
||||
this.memChart = new ApexCharts(this.$refs.mem, chartOpts);
|
||||
|
||||
this.cpuChart.render();
|
||||
this.memChart.render();
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.off('stats', this.onStats);
|
||||
this.connection.off('statsLog', this.onStatsLog);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onStats(stats) {
|
||||
this.stats.push(stats);
|
||||
if (this.stats.length > 200) this.stats.shift();
|
||||
|
||||
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
|
||||
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
|
||||
},
|
||||
|
||||
onStatsLog(statsLog) {
|
||||
statsLog.reverse().forEach(stats => this.onStats(stats));
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.zyknedwtlthezamcjlolyusmipqmjgxz
|
||||
display flex
|
||||
|
||||
> div
|
||||
display block
|
||||
flex 1
|
||||
padding 20px 12px 0 12px
|
||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||
background var(--face)
|
||||
border-radius 8px
|
||||
|
||||
&:first-child
|
||||
margin-right 16px
|
||||
|
||||
> header
|
||||
display flex
|
||||
padding 0 8px
|
||||
margin-bottom -16px
|
||||
color var(--adminDashboardCardFg)
|
||||
font-size 14px
|
||||
|
||||
> span
|
||||
&:last-child
|
||||
margin-left auto
|
||||
opacity 0.7
|
||||
|
||||
> span
|
||||
opacity 0.7
|
||||
|
||||
> div
|
||||
margin-bottom -10px
|
||||
|
||||
@media (max-width 1000px)
|
||||
display block
|
||||
margin-bottom 26px
|
||||
|
||||
> div
|
||||
&:first-child
|
||||
margin-right 0
|
||||
margin-bottom 26px
|
||||
|
||||
</style>
|
236
src/client/app/admin/views/dashboard.vue
Normal file
236
src/client/app/admin/views/dashboard.vue
Normal file
@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<div class="obdskegsannmntldydackcpzezagxqfy">
|
||||
<header v-if="meta">
|
||||
<p><b>Misskey</b><span>{{ meta.version }}</span></p>
|
||||
<p><b>Machine</b><span>{{ meta.machine }}</span></p>
|
||||
<p><b>OS</b><span>{{ meta.os }}</span></p>
|
||||
<p><b>Node</b><span>{{ meta.node }}</span></p>
|
||||
<p>%i18n:common.ai-chan-kawaii%</p>
|
||||
</header>
|
||||
|
||||
<div v-if="stats" class="stats">
|
||||
<div>
|
||||
<div>
|
||||
<div>%fa:user%</div>
|
||||
<div>
|
||||
<span>%i18n:@accounts%</span>
|
||||
<b class="primary">{{ stats.originalUsersCount | number }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>%fa:home% %i18n:@this-instance%</span>
|
||||
<span @click="setChartSrc('users')">%fa:chart-bar R%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>%fa:pencil-alt%</div>
|
||||
<div>
|
||||
<span>%i18n:@notes%</span>
|
||||
<b class="primary">{{ stats.originalNotesCount | number }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>%fa:home% %i18n:@this-instance%</span>
|
||||
<span @click="setChartSrc('notes')">%fa:chart-bar R%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>%fa:database%</div>
|
||||
<div>
|
||||
<span>%i18n:@drive%</span>
|
||||
<b>{{ stats.driveUsageLocal | bytes }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>%fa:home% %i18n:@this-instance%</span>
|
||||
<span @click="setChartSrc('drive')">%fa:chart-bar R%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>%fa:hdd R%</div>
|
||||
<div>
|
||||
<span>%i18n:@instances%</span>
|
||||
<b>{{ stats.instances | number }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>%fa:globe% %i18n:@federated%</span>
|
||||
<span @click="setChartSrc('federation-instances-total')">%fa:chart-bar R%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="charts">
|
||||
<x-charts ref="charts"/>
|
||||
</div>
|
||||
|
||||
<div class="cpu-memory">
|
||||
<x-cpu-memory :connection="connection"/>
|
||||
</div>
|
||||
|
||||
<div class="ap">
|
||||
<x-ap-log/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import XCpuMemory from "./cpu-memory.vue";
|
||||
import XCharts from "./charts.vue";
|
||||
import XApLog from "./ap-log.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XCpuMemory,
|
||||
XCharts,
|
||||
XApLog
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
stats: null,
|
||||
connection: null,
|
||||
meta: null
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.connection = (this as any).os.stream.useSharedConnection('serverStats');
|
||||
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.meta = meta;
|
||||
});
|
||||
|
||||
(this as any).api('stats').then(stats => {
|
||||
this.stats = stats;
|
||||
});
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.dispose();
|
||||
},
|
||||
|
||||
methods: {
|
||||
setChartSrc(src) {
|
||||
this.$refs.charts.setSrc(src);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.obdskegsannmntldydackcpzezagxqfy
|
||||
padding 16px
|
||||
|
||||
@media (min-width 500px)
|
||||
padding 32px
|
||||
|
||||
> header
|
||||
display flex
|
||||
margin-bottom 16px
|
||||
padding-bottom 16px
|
||||
border-bottom solid 1px var(--adminDashboardHeaderBorder)
|
||||
color var(--adminDashboardHeaderFg)
|
||||
font-size 14px
|
||||
white-space nowrap
|
||||
|
||||
@media (max-width 1000px)
|
||||
display none
|
||||
|
||||
> p
|
||||
display block
|
||||
margin 0 32px 0 0
|
||||
overflow hidden
|
||||
text-overflow ellipsis
|
||||
|
||||
> b
|
||||
&:after
|
||||
content ':'
|
||||
margin-right 8px
|
||||
|
||||
&:last-child
|
||||
margin-left auto
|
||||
margin-right 0
|
||||
|
||||
> .stats
|
||||
display flex
|
||||
justify-content space-between
|
||||
margin-bottom 16px
|
||||
|
||||
> div
|
||||
flex 1
|
||||
margin-right 16px
|
||||
color var(--adminDashboardCardFg)
|
||||
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
|
||||
background var(--adminDashboardCardBg)
|
||||
border-radius 8px
|
||||
|
||||
&:last-child
|
||||
margin-right 0
|
||||
|
||||
> div:first-child
|
||||
display flex
|
||||
align-items center
|
||||
text-align center
|
||||
|
||||
&:last-child
|
||||
margin-right 0
|
||||
|
||||
> div:first-child
|
||||
padding 16px 24px
|
||||
font-size 28px
|
||||
|
||||
> div:last-child
|
||||
flex 1
|
||||
padding 16px 32px 16px 0
|
||||
text-align right
|
||||
|
||||
> span
|
||||
font-size 70%
|
||||
opacity 0.7
|
||||
|
||||
> b
|
||||
display block
|
||||
|
||||
&.primary
|
||||
color var(--primary)
|
||||
|
||||
> div:last-child
|
||||
display flex
|
||||
padding 6px 16px
|
||||
border-top solid 1px var(--adminDashboardCardDivider)
|
||||
|
||||
> span
|
||||
font-size 70%
|
||||
opacity 0.7
|
||||
|
||||
&:last-child
|
||||
margin-left auto
|
||||
cursor pointer
|
||||
|
||||
@media (max-width 900px)
|
||||
display grid
|
||||
grid-template-columns 1fr 1fr
|
||||
grid-template-rows 1fr 1fr
|
||||
gap 16px
|
||||
|
||||
> div
|
||||
margin-right 0
|
||||
|
||||
@media (max-width 500px)
|
||||
display block
|
||||
|
||||
> div:not(:last-child)
|
||||
margin-bottom 16px
|
||||
|
||||
> .charts
|
||||
margin-bottom 16px
|
||||
|
||||
> .cpu-memory
|
||||
margin-bottom 16px
|
||||
|
||||
</style>
|
117
src/client/app/admin/views/emoji.vue
Normal file
117
src/client/app/admin/views/emoji.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
|
||||
<ui-card>
|
||||
<div slot="title">%fa:plus% %i18n:@add-emoji.title%</div>
|
||||
<section class="fit-top">
|
||||
<ui-horizon-group inputs>
|
||||
<ui-input v-model="name">
|
||||
<span>%i18n:@add-emoji.name%</span>
|
||||
<span slot="text">%i18n:@add-emoji.name-desc%</span>
|
||||
</ui-input>
|
||||
<ui-input v-model="aliases">
|
||||
<span>%i18n:@add-emoji.aliases%</span>
|
||||
<span slot="text">%i18n:@add-emoji.aliases-desc%</span>
|
||||
</ui-input>
|
||||
</ui-horizon-group>
|
||||
<ui-input v-model="url">
|
||||
<span>%i18n:@add-emoji.url%</span>
|
||||
</ui-input>
|
||||
<ui-button @click="add">%i18n:@add-emoji.add%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%fa:grin R% %i18n:@emojis.title%</div>
|
||||
<section v-for="emoji in emojis">
|
||||
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
|
||||
<ui-horizon-group inputs>
|
||||
<ui-input v-model="emoji.name">
|
||||
<span>%i18n:@add-emoji.name%</span>
|
||||
</ui-input>
|
||||
<ui-input v-model="emoji.aliases">
|
||||
<span>%i18n:@add-emoji.aliases%</span>
|
||||
</ui-input>
|
||||
</ui-horizon-group>
|
||||
<ui-input v-model="emoji.url">
|
||||
<span>%i18n:@add-emoji.url%</span>
|
||||
</ui-input>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="updateEmoji(emoji)">%fa:save R% %i18n:@emojis.update%</ui-button>
|
||||
<ui-button @click="removeEmoji(emoji)">%fa:trash-alt R% %i18n:@emojis.remove%</ui-button>
|
||||
</ui-horizon-group>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
url: '',
|
||||
aliases: '',
|
||||
emojis: []
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fetchEmojis();
|
||||
},
|
||||
|
||||
methods: {
|
||||
add() {
|
||||
(this as any).api('admin/emoji/add', {
|
||||
name: this.name,
|
||||
url: this.url,
|
||||
aliases: this.aliases.split(' ')
|
||||
}).then(() => {
|
||||
//(this as any).os.apis.dialog({ text: `Added` });
|
||||
this.fetchEmojis();
|
||||
}).catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
},
|
||||
|
||||
fetchEmojis() {
|
||||
(this as any).api('admin/emoji/list').then(emojis => {
|
||||
emojis.forEach(e => e.aliases = (e.aliases || []).join(' '));
|
||||
this.emojis = emojis;
|
||||
});
|
||||
},
|
||||
|
||||
updateEmoji(emoji) {
|
||||
(this as any).api('admin/emoji/update', {
|
||||
id: emoji.id,
|
||||
name: emoji.name,
|
||||
url: emoji.url,
|
||||
aliases: emoji.aliases.split(' ')
|
||||
}).then(() => {
|
||||
//(this as any).os.apis.dialog({ text: `Updated` });
|
||||
}).catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
},
|
||||
|
||||
removeEmoji(emoji) {
|
||||
(this as any).api('admin/emoji/remove', {
|
||||
id: emoji.id
|
||||
}).then(() => {
|
||||
//(this as any).os.apis.dialog({ text: `Removed` });
|
||||
this.fetchEmojis();
|
||||
}).catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tumhkfkmgtvzljezfvmgkeurkfncshbe
|
||||
@media (min-width 500px)
|
||||
padding 16px
|
||||
|
||||
</style>
|
@ -1,8 +1,12 @@
|
||||
<template>
|
||||
<div class="jdnqwkzlnxcfftthoybjxrebyolvoucw mk-admin-card">
|
||||
<header>%i18n:@hided-tags%</header>
|
||||
<textarea v-model="hidedTags"></textarea>
|
||||
<button class="ui" @click="save">%i18n:@save%</button>
|
||||
<div>
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@hided-tags%</div>
|
||||
<section>
|
||||
<textarea class="jdnqwkzlnxcfftthoybjxrebyolvoucw" v-model="hidedTags"></textarea>
|
||||
<ui-button @click="save">%i18n:@save%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -25,9 +29,9 @@ export default Vue.extend({
|
||||
(this as any).api('admin/update-meta', {
|
||||
hidedTags: this.hidedTags.split('\n')
|
||||
}).then(() => {
|
||||
(this as any).os.apis.dialog({ text: `Saved` });
|
||||
//(this as any).os.apis.dialog({ text: `Saved` });
|
||||
}).catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -35,11 +39,8 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
|
||||
.jdnqwkzlnxcfftthoybjxrebyolvoucw
|
||||
textarea
|
||||
width 100%
|
||||
min-height 300px
|
||||
width 100%
|
||||
min-height 300px
|
||||
|
||||
</style>
|
260
src/client/app/admin/views/index.vue
Normal file
260
src/client/app/admin/views/index.vue
Normal file
@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div class="mk-admin" :class="{ isMobile }">
|
||||
<header v-show="isMobile">
|
||||
<button class="nav" @click="navOpend = true">%fa:bars%</button>
|
||||
<span>MisskeyMyAdmin</span>
|
||||
</header>
|
||||
<div class="nav-backdrop"
|
||||
v-if="navOpend && isMobile"
|
||||
@click="navOpend = false"
|
||||
@touchstart="navOpend = false"
|
||||
></div>
|
||||
<nav v-show="navOpend">
|
||||
<div class="mi">
|
||||
<img svg-inline src="../assets/header-icon.svg"/>
|
||||
</div>
|
||||
<div class="me">
|
||||
<img class="avatar" :src="$store.state.i.avatarUrl" alt="avatar"/>
|
||||
<p class="name">{{ $store.state.i | userName }}</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:home .fw%%i18n:@dashboard%</li>
|
||||
<li @click="nav('instance')" :class="{ active: page == 'instance' }">%fa:cog .fw%%i18n:@instance%</li>
|
||||
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
|
||||
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }">%fa:grin R .fw%%i18n:@emoji%</li>
|
||||
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
|
||||
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li>
|
||||
|
||||
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> -->
|
||||
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
|
||||
</ul>
|
||||
<div class="back-to-misskey">
|
||||
<a href="/">%fa:arrow-left% %i18n:@back-to-misskey%</a>
|
||||
</div>
|
||||
<div class="version">
|
||||
<small>Misskey {{ version }}</small>
|
||||
</div>
|
||||
</nav>
|
||||
<main>
|
||||
<div v-show="page == 'dashboard'"><x-dashboard/></div>
|
||||
<div v-show="page == 'instance'"><x-instance/></div>
|
||||
<div v-if="page == 'users'"><x-users/></div>
|
||||
<div v-show="page == 'emoji'"><x-emoji/></div>
|
||||
<div v-show="page == 'announcements'"><x-announcements/></div>
|
||||
<div v-show="page == 'hashtags'"><x-hashtags/></div>
|
||||
<div v-if="page == 'drive'"></div>
|
||||
<div v-if="page == 'update'"></div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { version } from '../../config';
|
||||
import XDashboard from "./dashboard.vue";
|
||||
import XInstance from "./instance.vue";
|
||||
import XEmoji from "./emoji.vue";
|
||||
import XAnnouncements from "./announcements.vue";
|
||||
import XHashtags from "./hashtags.vue";
|
||||
import XUsers from "./users.vue";
|
||||
|
||||
// Detect the user agent
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
const isMobile = /mobile|iphone|ipad|android/.test(ua);
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XDashboard,
|
||||
XInstance,
|
||||
XEmoji,
|
||||
XAnnouncements,
|
||||
XHashtags,
|
||||
XUsers
|
||||
},
|
||||
provide: {
|
||||
isMobile
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page: 'dashboard',
|
||||
version,
|
||||
isMobile,
|
||||
navOpend: !isMobile
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
nav(page: string) {
|
||||
this.page = page;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.mk-admin
|
||||
$headerHeight = 48px
|
||||
|
||||
display flex
|
||||
height 100%
|
||||
|
||||
> header
|
||||
position fixed
|
||||
top 0
|
||||
z-index 10000
|
||||
width 100%
|
||||
color var(--mobileHeaderFg)
|
||||
background-color var(--mobileHeaderBg)
|
||||
box-shadow 0 1px 0 rgba(#000, 0.075)
|
||||
|
||||
&, *
|
||||
user-select none
|
||||
|
||||
> span
|
||||
display block
|
||||
line-height $headerHeight
|
||||
text-align center
|
||||
|
||||
> .nav
|
||||
display block
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
z-index 10001
|
||||
padding 0
|
||||
width $headerHeight
|
||||
font-size 1.4em
|
||||
line-height $headerHeight
|
||||
border-right solid 1px rgba(#000, 0.1)
|
||||
|
||||
> [data-fa]
|
||||
transition all 0.2s ease
|
||||
|
||||
> nav
|
||||
position fixed
|
||||
z-index 20001
|
||||
top 0
|
||||
left 0
|
||||
width 250px
|
||||
height 100vh
|
||||
overflow auto
|
||||
background #333
|
||||
color #fff
|
||||
|
||||
> .mi
|
||||
text-align center
|
||||
|
||||
> svg
|
||||
width 24px
|
||||
height 82px
|
||||
vertical-align top
|
||||
fill #fff
|
||||
opacity 0.7
|
||||
|
||||
> .me
|
||||
display flex
|
||||
margin 0 16px 16px 16px
|
||||
padding 16px 0
|
||||
align-items center
|
||||
border-top solid 1px #555
|
||||
border-bottom solid 1px #555
|
||||
|
||||
> .avatar
|
||||
height 48px
|
||||
border-radius 100%
|
||||
vertical-align middle
|
||||
|
||||
> .name
|
||||
margin 0 16px
|
||||
padding 0
|
||||
color #fff
|
||||
overflow hidden
|
||||
text-overflow ellipsis
|
||||
white-space nowrap
|
||||
font-size 15px
|
||||
|
||||
> .back-to-misskey
|
||||
margin 16px 16px 0 16px
|
||||
padding 0
|
||||
border-top solid 1px #555
|
||||
|
||||
> a
|
||||
display block
|
||||
padding 16px 4px
|
||||
color inherit
|
||||
text-decoration none
|
||||
color #eee
|
||||
font-size 15px
|
||||
|
||||
&:hover
|
||||
color #fff
|
||||
|
||||
> [data-fa]
|
||||
margin-right 6px
|
||||
|
||||
> .version
|
||||
margin 0 16px 16px 16px
|
||||
padding-top 16px
|
||||
border-top solid 1px #555
|
||||
text-align center
|
||||
|
||||
> small
|
||||
opacity 0.7
|
||||
|
||||
> ul
|
||||
margin 0
|
||||
padding 0
|
||||
list-style none
|
||||
font-size 15px
|
||||
|
||||
> li
|
||||
display block
|
||||
padding 10px 16px
|
||||
margin 0
|
||||
cursor pointer
|
||||
user-select none
|
||||
color #eee
|
||||
transition margin-left 0.2s ease
|
||||
|
||||
&:hover
|
||||
color #fff
|
||||
|
||||
> [data-fa]
|
||||
margin-right 6px
|
||||
|
||||
&.active
|
||||
margin-left 8px
|
||||
color var(--primary) !important
|
||||
|
||||
&:after
|
||||
content ""
|
||||
display block
|
||||
position absolute
|
||||
top 0
|
||||
right 0
|
||||
bottom 0
|
||||
margin auto 0
|
||||
height 0
|
||||
border-top solid 16px transparent
|
||||
border-right solid 16px var(--bg)
|
||||
border-bottom solid 16px transparent
|
||||
border-left solid 16px transparent
|
||||
|
||||
> .nav-backdrop
|
||||
position fixed
|
||||
top 0
|
||||
left 0
|
||||
z-index 20000
|
||||
width 100%
|
||||
height 100%
|
||||
background var(--mobileNavBackdrop)
|
||||
|
||||
> main
|
||||
width 100%
|
||||
padding 0 0 0 250px
|
||||
max-width 1300px
|
||||
|
||||
&.isMobile
|
||||
> main
|
||||
padding $headerHeight 0 0 0
|
||||
|
||||
</style>
|
85
src/client/app/admin/views/instance.vue
Normal file
85
src/client/app/admin/views/instance.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div class="axbwjelsbymowqjyywpirzhdlszoncqs">
|
||||
<ui-card>
|
||||
<div slot="title">%fa:cog% %i18n:@instance%</div>
|
||||
<section class="fit-top">
|
||||
<ui-input v-model="name">%i18n:@instance-name%</ui-input>
|
||||
<ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea>
|
||||
<ui-input v-model="bannerUrl">%i18n:@banner-url%</ui-input>
|
||||
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@disable-registration%</div>
|
||||
<section>
|
||||
<input type="checkbox" v-model="disableRegistration" @change="updateMeta">
|
||||
<button class="ui" @click="invite">%i18n:@invite%</button>
|
||||
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@disable-local-timeline%</div>
|
||||
<section>
|
||||
<input type="checkbox" v-model="disableLocalTimeline" @change="updateMeta">
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
disableRegistration: false,
|
||||
disableLocalTimeline: false,
|
||||
bannerUrl: null,
|
||||
name: null,
|
||||
description: null,
|
||||
inviteCode: null,
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.bannerUrl = meta.bannerUrl;
|
||||
this.name = meta.name;
|
||||
this.description = meta.description;
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
invite() {
|
||||
(this as any).api('admin/invite').then(x => {
|
||||
this.inviteCode = x.code;
|
||||
}).catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
},
|
||||
|
||||
updateMeta() {
|
||||
(this as any).api('admin/update-meta', {
|
||||
disableRegistration: this.disableRegistration,
|
||||
disableLocalTimeline: this.disableLocalTimeline,
|
||||
bannerUrl: this.bannerUrl,
|
||||
name: this.name,
|
||||
description: this.description
|
||||
}).then(() => {
|
||||
//(this as any).os.apis.dialog({ text: `Saved` });
|
||||
}).catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.axbwjelsbymowqjyywpirzhdlszoncqs
|
||||
@media (min-width 500px)
|
||||
padding 16px
|
||||
|
||||
</style>
|
136
src/client/app/admin/views/users.vue
Normal file
136
src/client/app/admin/views/users.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="ucnffhbtogqgscfmqcymwmmupoknpfsw">
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@verify-user%</div>
|
||||
<section class="fit-top">
|
||||
<ui-input v-model="verifyUsername" type="text">
|
||||
<span slot="prefix">@</span>
|
||||
</ui-input>
|
||||
<ui-button @click="verifyUser" :disabled="verifying">%i18n:@verify%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@unverify-user%</div>
|
||||
<section class="fit-top">
|
||||
<ui-input v-model="unverifyUsername" type="text">
|
||||
<span slot="prefix">@</span>
|
||||
</ui-input>
|
||||
<ui-button @click="unverifyUser" :disabled="unverifying">%i18n:@unverify%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@suspend-user%</div>
|
||||
<section class="fit-top">
|
||||
<ui-input v-model="suspendUsername" type="text">
|
||||
<span slot="prefix">@</span>
|
||||
</ui-input>
|
||||
<ui-button @click="suspendUser" :disabled="suspending">%i18n:@suspend%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%i18n:@unsuspend-user%</div>
|
||||
<section class="fit-top">
|
||||
<ui-input v-model="unsuspendUsername" type="text">
|
||||
<span slot="prefix">@</span>
|
||||
</ui-input>
|
||||
<ui-button @click="unsuspendUser" :disabled="unsuspending">%i18n:@unsuspend%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import parseAcct from "../../../../misc/acct/parse";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
verifyUsername: null,
|
||||
verifying: false,
|
||||
unverifyUsername: null,
|
||||
unverifying: false,
|
||||
suspendUsername: null,
|
||||
suspending: false,
|
||||
unsuspendUsername: null,
|
||||
unsuspending: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
async verifyUser() {
|
||||
this.verifying = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api('users/show', parseAcct(this.verifyUsername));
|
||||
await (this as any).os.api('admin/verify-user', { userId: user.id });
|
||||
//(this as any).os.apis.dialog({ text: '%i18n:@verified%' });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.verifying = false;
|
||||
},
|
||||
|
||||
async unverifyUser() {
|
||||
this.unverifying = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api('users/show', parseAcct(this.unverifyUsername));
|
||||
await (this as any).os.api('admin/unverify-user', { userId: user.id });
|
||||
//(this as any).os.apis.dialog({ text: '%i18n:@unverified%' });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.unverifying = false;
|
||||
},
|
||||
|
||||
async suspendUser() {
|
||||
this.suspending = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api('users/show', parseAcct(this.suspendUsername));
|
||||
await (this as any).os.api('admin/suspend-user', { userId: user.id });
|
||||
//(this as any).os.apis.dialog({ text: '%i18n:@suspended%' });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.suspending = false;
|
||||
},
|
||||
|
||||
async unsuspendUser() {
|
||||
this.unsuspending = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api('users/show', parseAcct(this.unsuspendUsername));
|
||||
await (this as any).os.api('admin/unsuspend-user', { userId: user.id });
|
||||
//(this as any).os.apis.dialog({ text: '%i18n:@unsuspended%' });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
//(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.unsuspending = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.ucnffhbtogqgscfmqcymwmmupoknpfsw
|
||||
@media (min-width 500px)
|
||||
padding 16px
|
||||
|
||||
</style>
|
@ -46,6 +46,7 @@
|
||||
if (`${url.pathname}/`.startsWith('/docs/')) app = 'docs';
|
||||
if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
|
||||
if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
|
||||
if (`${url.pathname}/`.startsWith('/admin/')) app = 'admin';
|
||||
//#endregion
|
||||
|
||||
//#region Detect the user language
|
||||
|
@ -1,5 +1,5 @@
|
||||
import MiOS from '../../mios';
|
||||
import { version as current } from '../../config';
|
||||
import { clientVersion as current } from '../../config';
|
||||
|
||||
export default async function(mios: MiOS, force = false, silent = false) {
|
||||
const meta = await mios.getMeta(force);
|
||||
|
72
src/client/app/common/views/components/api-settings.vue
Normal file
72
src/client/app/common/views/components/api-settings.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<ui-card>
|
||||
<div slot="title">%fa:key% API</div>
|
||||
|
||||
<section class="fit-top">
|
||||
<ui-input :value="$store.state.i.token" readonly>
|
||||
<span>%i18n:@token%</span>
|
||||
</ui-input>
|
||||
<p>%i18n:@intro%</p>
|
||||
<ui-info warn>%i18n:@caution%</ui-info>
|
||||
<p>%i18n:@regeneration-of-token%</p>
|
||||
<ui-button @click="regenerateToken">%fa:sync-alt% %i18n:@regenerate-token%</ui-button>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<header>%fa:terminal% %i18n:@console.title%</header>
|
||||
<ui-input v-model="endpoint">
|
||||
<span>%i18n:@console.endpoint%</span>
|
||||
</ui-input>
|
||||
<ui-textarea v-model="body">
|
||||
<span>%i18n:@console.parameter% (JSON or JSON5)</span>
|
||||
</ui-textarea>
|
||||
<ui-button @click="send" :disabled="sending">
|
||||
<template v-if="sending">%i18n:@console.sending%</template>
|
||||
<template v-else>%fa:paper-plane% %i18n:@console.send%</template>
|
||||
</ui-button>
|
||||
<ui-textarea v-if="res" v-model="res" readonly tall>
|
||||
<span>%i18n:@console.response%</span>
|
||||
</ui-textarea>
|
||||
</section>
|
||||
</ui-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as JSON5 from 'json5';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
endpoint: '',
|
||||
body: '{}',
|
||||
res: null,
|
||||
sending: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
regenerateToken() {
|
||||
(this as any).apis.input({
|
||||
title: '%i18n:@enter-password%',
|
||||
type: 'password'
|
||||
}).then(password => {
|
||||
(this as any).api('i/regenerate_token', {
|
||||
password: password
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
send() {
|
||||
this.sending = true;
|
||||
(this as any).api(this.endpoint, JSON5.parse(this.body)).then(res => {
|
||||
this.sending = false;
|
||||
this.res = JSON5.stringify(res, null, 2);
|
||||
}, err => {
|
||||
this.sending = false;
|
||||
this.res = JSON5.stringify(err, null, 2);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -14,9 +14,10 @@
|
||||
</ol>
|
||||
<ol class="emojis" ref="suggests" v-if="emojis.length > 0">
|
||||
<li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1">
|
||||
<span class="emoji">{{ emoji.emoji }}</span>
|
||||
<span class="emoji" v-if="emoji.url"><img :src="emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span class="emoji" v-else>{{ emoji.emoji }}</span>
|
||||
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
|
||||
<span class="alias" v-if="emoji.alias">({{ emoji.alias }})</span>
|
||||
<span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
@ -27,14 +28,21 @@ import Vue from 'vue';
|
||||
import * as emojilib from 'emojilib';
|
||||
import contains from '../../../common/scripts/contains';
|
||||
|
||||
type EmojiDef = {
|
||||
emoji: string;
|
||||
name: string;
|
||||
aliasOf?: string;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
const lib = Object.entries(emojilib.lib).filter((x: any) => {
|
||||
return x[1].category != 'flags';
|
||||
});
|
||||
|
||||
const emjdb = lib.map((x: any) => ({
|
||||
const emjdb: EmojiDef[] = lib.map((x: any) => ({
|
||||
emoji: x[1].char,
|
||||
name: x[0],
|
||||
alias: null
|
||||
aliasOf: null
|
||||
}));
|
||||
|
||||
lib.forEach((x: any) => {
|
||||
@ -43,7 +51,7 @@ lib.forEach((x: any) => {
|
||||
emjdb.push({
|
||||
emoji: x[1].char,
|
||||
name: k,
|
||||
alias: x[0]
|
||||
aliasOf: x[0]
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -61,7 +69,8 @@ export default Vue.extend({
|
||||
hashtags: [],
|
||||
emojis: [],
|
||||
select: -1,
|
||||
emojilib
|
||||
emojilib,
|
||||
emojiDb: [] as EmojiDef[]
|
||||
}
|
||||
},
|
||||
|
||||
@ -90,6 +99,34 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
mounted() {
|
||||
//#region Construct Emoji DB
|
||||
const customEmojis = (this.os.getMetaSync() || { emojis: [] }).emojis || [];
|
||||
const emojiDefinitions: EmojiDef[] = [];
|
||||
|
||||
customEmojis.forEach(x => {
|
||||
emojiDefinitions.push({
|
||||
name: x.name,
|
||||
emoji: `:${x.name}:`,
|
||||
url: x.url
|
||||
});
|
||||
|
||||
if (x.aliases) {
|
||||
x.aliases.forEach(alias => {
|
||||
emojiDefinitions.push({
|
||||
name: alias,
|
||||
aliasOf: x.name,
|
||||
emoji: `:${x.name}:`,
|
||||
url: x.url
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
|
||||
|
||||
this.emojiDb = emojiDefinitions.concat(emjdb);
|
||||
//#endregion
|
||||
|
||||
this.textarea.addEventListener('keydown', this.onKeydown);
|
||||
|
||||
Array.from(document.querySelectorAll('body *')).forEach(el => {
|
||||
@ -169,22 +206,25 @@ export default Vue.extend({
|
||||
}
|
||||
} else if (this.type == 'emoji') {
|
||||
const matched = [];
|
||||
emjdb.some(x => {
|
||||
if (x.name.indexOf(this.q) == 0 && !x.alias && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
|
||||
return matched.length == 30;
|
||||
const max = 30;
|
||||
|
||||
this.emojiDb.some(x => {
|
||||
if (x.name.startsWith(this.q) && !x.aliasOf && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
|
||||
return matched.length == max;
|
||||
});
|
||||
if (matched.length < 30) {
|
||||
emjdb.some(x => {
|
||||
if (x.name.indexOf(this.q) == 0 && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
|
||||
return matched.length == 30;
|
||||
if (matched.length < max) {
|
||||
this.emojiDb.some(x => {
|
||||
if (x.name.startsWith(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
|
||||
return matched.length == max;
|
||||
});
|
||||
}
|
||||
if (matched.length < 30) {
|
||||
emjdb.some(x => {
|
||||
if (x.name.indexOf(this.q) > -1 && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
|
||||
return matched.length == 30;
|
||||
if (matched.length < max) {
|
||||
this.emojiDb.some(x => {
|
||||
if (x.name.includes(this.q) && !matched.some(y => y.emoji == x.emoji)) matched.push(x);
|
||||
return matched.length == max;
|
||||
});
|
||||
}
|
||||
|
||||
this.emojis = matched;
|
||||
}
|
||||
},
|
||||
@ -340,6 +380,10 @@ export default Vue.extend({
|
||||
margin 0 4px 0 0
|
||||
width 24px
|
||||
|
||||
> img
|
||||
width 24px
|
||||
vertical-align bottom
|
||||
|
||||
.name
|
||||
color var(--autocompleteItemText)
|
||||
|
||||
|
19
src/client/app/common/views/components/error.vue
Normal file
19
src/client/app/common/views/components/error.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj">
|
||||
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
|
||||
<ui-button @click="() => $emit('retry')">%i18n:common.error.retry%</ui-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.wjqjnyhzogztorhrdgcpqlkxhkmuetgj
|
||||
max-width 350px
|
||||
margin 0 auto
|
||||
padding 32px
|
||||
text-align center
|
||||
color var(--text)
|
||||
|
||||
> p
|
||||
margin 0 0 8px 0
|
||||
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="View source on Github">
|
||||
<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="View source on GitHub">
|
||||
<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
|
||||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
||||
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path>
|
||||
|
63
src/client/app/common/views/components/github-setting.vue
Normal file
63
src/client/app/common/views/components/github-setting.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="mk-github-setting">
|
||||
<p>%i18n:@description%<a :href="`${docsUrl}/link-to-github`" target="_blank">%i18n:@detail%</a></p>
|
||||
<p class="account" v-if="$store.state.i.github" :title="`GitHub ID: ${$store.state.i.github.id}`">%i18n:@connected-to%: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
|
||||
<p>
|
||||
<a :href="`${apiUrl}/connect/github`" target="_blank" @click.prevent="connect">{{ $store.state.i.github ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
|
||||
<span v-if="$store.state.i.github"> or </span>
|
||||
<a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github" @click.prevent="disconnect">%i18n:@disconnect%</a>
|
||||
</p>
|
||||
<p class="id" v-if="$store.state.i.github">GitHub ID: {{ $store.state.i.github.id }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { apiUrl, docsUrl } from '../../../config';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
form: null,
|
||||
apiUrl,
|
||||
docsUrl
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$watch('$store.state.i', () => {
|
||||
if (this.$store.state.i.github && this.form)
|
||||
this.form.close();
|
||||
}, {
|
||||
deep: true
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
connect() {
|
||||
this.form = window.open(apiUrl + '/connect/github',
|
||||
'github_connect_window',
|
||||
'height=570, width=520');
|
||||
},
|
||||
|
||||
disconnect() {
|
||||
window.open(apiUrl + '/disconnect/github',
|
||||
'github_disconnect_window',
|
||||
'height=570, width=520');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mk-github-setting
|
||||
.account
|
||||
border solid 1px #e1e8ed
|
||||
border-radius 4px
|
||||
padding 16px
|
||||
|
||||
a
|
||||
font-weight bold
|
||||
color inherit
|
||||
|
||||
.id
|
||||
color #8899a6
|
||||
</style>
|
@ -1,5 +1,9 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
import muteAndBlock from './mute-and-block.vue';
|
||||
import error from './error.vue';
|
||||
import apiSettings from './api-settings.vue';
|
||||
import passwordSettings from './password-settings.vue';
|
||||
import driveSettings from './drive-settings.vue';
|
||||
import profileEditor from './profile-editor.vue';
|
||||
import noteSkeleton from './note-skeleton.vue';
|
||||
@ -33,20 +37,27 @@ import messaging from './messaging.vue';
|
||||
import messagingRoom from './messaging-room.vue';
|
||||
import urlPreview from './url-preview.vue';
|
||||
import twitterSetting from './twitter-setting.vue';
|
||||
import githubSetting from './github-setting.vue';
|
||||
import fileTypeIcon from './file-type-icon.vue';
|
||||
import Reversi from './games/reversi/reversi.vue';
|
||||
import welcomeTimeline from './welcome-timeline.vue';
|
||||
import uiInput from './ui/input.vue';
|
||||
import uiButton from './ui/button.vue';
|
||||
import uiHorizonGroup from './ui/horizon-group.vue';
|
||||
import uiCard from './ui/card.vue';
|
||||
import uiForm from './ui/form.vue';
|
||||
import uiTextarea from './ui/textarea.vue';
|
||||
import uiSwitch from './ui/switch.vue';
|
||||
import uiRadio from './ui/radio.vue';
|
||||
import uiSelect from './ui/select.vue';
|
||||
import uiInfo from './ui/info.vue';
|
||||
import formButton from './ui/form/button.vue';
|
||||
import formRadio from './ui/form/radio.vue';
|
||||
|
||||
Vue.component('mk-mute-and-block', muteAndBlock);
|
||||
Vue.component('mk-error', error);
|
||||
Vue.component('mk-api-settings', apiSettings);
|
||||
Vue.component('mk-password-settings', passwordSettings);
|
||||
Vue.component('mk-drive-settings', driveSettings);
|
||||
Vue.component('mk-profile-editor', profileEditor);
|
||||
Vue.component('mk-note-skeleton', noteSkeleton);
|
||||
@ -80,16 +91,19 @@ Vue.component('mk-messaging', messaging);
|
||||
Vue.component('mk-messaging-room', messagingRoom);
|
||||
Vue.component('mk-url-preview', urlPreview);
|
||||
Vue.component('mk-twitter-setting', twitterSetting);
|
||||
Vue.component('mk-github-setting', githubSetting);
|
||||
Vue.component('mk-file-type-icon', fileTypeIcon);
|
||||
Vue.component('mk-reversi', Reversi);
|
||||
Vue.component('mk-welcome-timeline', welcomeTimeline);
|
||||
Vue.component('ui-input', uiInput);
|
||||
Vue.component('ui-button', uiButton);
|
||||
Vue.component('ui-horizon-group', uiHorizonGroup);
|
||||
Vue.component('ui-card', uiCard);
|
||||
Vue.component('ui-form', uiForm);
|
||||
Vue.component('ui-textarea', uiTextarea);
|
||||
Vue.component('ui-switch', uiSwitch);
|
||||
Vue.component('ui-radio', uiRadio);
|
||||
Vue.component('ui-select', uiSelect);
|
||||
Vue.component('ui-info', uiInfo);
|
||||
Vue.component('form-button', formButton);
|
||||
Vue.component('form-radio', formRadio);
|
||||
|
@ -3,7 +3,6 @@ import * as emojilib from 'emojilib';
|
||||
import { length } from 'stringz';
|
||||
import parse from '../../../../../mfm/parse';
|
||||
import getAcct from '../../../../../misc/acct/render';
|
||||
import { url } from '../../../config';
|
||||
import MkUrl from './url.vue';
|
||||
import MkGoogle from './google.vue';
|
||||
import { concat } from '../../../../../prelude/array';
|
||||
@ -25,6 +24,9 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
i: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
customEmojis: {
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -186,6 +188,22 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
}
|
||||
|
||||
case 'emoji': {
|
||||
//#region カスタム絵文字
|
||||
if (this.customEmojis != null) {
|
||||
const customEmoji = this.customEmojis.find(e => e.name == token.emoji || (e.aliases || []).includes(token.emoji));
|
||||
if (customEmoji) {
|
||||
return [createElement('img', {
|
||||
attrs: {
|
||||
src: customEmoji.url,
|
||||
alt: token.emoji,
|
||||
title: token.emoji,
|
||||
style: 'height: 2.5em; vertical-align: middle;'
|
||||
}
|
||||
})];
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
const emoji = emojilib.lib[token.emoji];
|
||||
return [createElement('span', emoji ? emoji.char : token.content)];
|
||||
}
|
||||
|
52
src/client/app/common/views/components/mute-and-block.vue
Normal file
52
src/client/app/common/views/components/mute-and-block.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<ui-card>
|
||||
<div slot="title">%fa:ban% %i18n:@mute-and-block%</div>
|
||||
|
||||
<section>
|
||||
<header>%i18n:@mute%</header>
|
||||
<ui-info v-if="!muteFetching && mute.length == 0">%i18n:@no-muted-users%</ui-info>
|
||||
<div class="users" v-if="mute.length != 0">
|
||||
<div v-for="user in mute" :key="user.id">
|
||||
<p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<header>%i18n:@block%</header>
|
||||
<ui-info v-if="!blockFetching && block.length == 0">%i18n:@no-blocked-users%</ui-info>
|
||||
<div class="users" v-if="block.length != 0">
|
||||
<div v-for="user in block" :key="user.id">
|
||||
<p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ui-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
muteFetching: true,
|
||||
blockFetching: true,
|
||||
mute: [],
|
||||
block: []
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
(this as any).api('mute/list').then(mute => {
|
||||
this.mute = mute.map(x => x.mutee);
|
||||
this.muteFetching = false;
|
||||
});
|
||||
|
||||
(this as any).api('blocking/list').then(blocking => {
|
||||
this.block = blocking.map(x => x.blockee);
|
||||
this.blockFetching = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
@ -2,8 +2,6 @@
|
||||
<span class="mk-nav">
|
||||
<a :href="aboutUrl">%i18n:@about%</a>
|
||||
<i>・</i>
|
||||
<a href="/stats">%i18n:@stats%</a>
|
||||
<i>・</i>
|
||||
<a :href="repositoryUrl">%i18n:@repository%</a>
|
||||
<i>・</i>
|
||||
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a>
|
||||
|
@ -2,11 +2,11 @@
|
||||
<header class="bvonvjxbwzaiskogyhbwgyxvcgserpmu">
|
||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/>
|
||||
<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
|
||||
<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%">%fa:star%</span>
|
||||
<span class="is-admin" v-if="note.user.isAdmin">admin</span>
|
||||
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
||||
<span class="is-cat" v-if="note.user.isCat">cat</span>
|
||||
<span class="username"><mk-acct :user="note.user"/></span>
|
||||
<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%">%fa:star%</span>
|
||||
<div class="info">
|
||||
<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span>
|
||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
||||
@ -68,10 +68,6 @@ export default Vue.extend({
|
||||
&:hover
|
||||
text-decoration underline
|
||||
|
||||
> .is-verified
|
||||
margin-right 8px
|
||||
color #4dabf7
|
||||
|
||||
> .is-admin
|
||||
> .is-bot
|
||||
> .is-cat
|
||||
@ -95,6 +91,10 @@ export default Vue.extend({
|
||||
color var(--noteHeaderAcct)
|
||||
flex-shrink 2147483647
|
||||
|
||||
> .is-verified
|
||||
margin 0 .5em 0 0
|
||||
color #4dabf7
|
||||
|
||||
> .info
|
||||
margin-left auto
|
||||
font-size 0.9em
|
||||
|
@ -13,6 +13,7 @@
|
||||
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/>
|
||||
<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button>
|
||||
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p>
|
||||
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/github`">%i18n:@signin-with-github%</a></p>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr" :is="link ? 'a' : 'button'" :class="[styl, { inline, primary }]" :type="type" @click="$emit('click')">
|
||||
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr"
|
||||
:is="link ? 'a' : 'button'"
|
||||
:class="[styl, { inline, primary }]"
|
||||
:type="type"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<slot></slot>
|
||||
</component>
|
||||
</template>
|
||||
@ -7,6 +12,7 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
export default Vue.extend({
|
||||
inject: ['horizonGrouped'],
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
@ -20,7 +26,9 @@ export default Vue.extend({
|
||||
inline: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
default(): boolean {
|
||||
return this.horizonGrouped;
|
||||
}
|
||||
},
|
||||
link: {
|
||||
type: Boolean,
|
||||
|
35
src/client/app/common/views/components/ui/horizon-group.vue
Normal file
35
src/client/app/common/views/components/ui/horizon-group.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="pfzekjfwkwvadvlujpdnnxfggqgqjoze" :class="{ inputs }">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
export default Vue.extend({
|
||||
provide: {
|
||||
horizonGrouped: true
|
||||
},
|
||||
props: {
|
||||
inputs: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.pfzekjfwkwvadvlujpdnnxfggqgqjoze
|
||||
display flex
|
||||
|
||||
&.inputs
|
||||
margin 32px 0
|
||||
|
||||
> *
|
||||
flex 1
|
||||
|
||||
&:not(:last-child)
|
||||
margin-right 16px
|
||||
</style>
|
43
src/client/app/common/views/components/ui/info.vue
Normal file
43
src/client/app/common/views/components/ui/info.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="ymxyweixqwsxauxldgpvecjepnwxbylu" :class="{ warn }">
|
||||
<i v-if="warn">%fa:exclamation-triangle%</i>
|
||||
<i v-else>%fa:info-circle%</i>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
warn: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.ymxyweixqwsxauxldgpvecjepnwxbylu
|
||||
margin 16px 0
|
||||
padding 16px
|
||||
font-size 90%
|
||||
background var(--infoBg)
|
||||
color var(--infoFg)
|
||||
|
||||
&.warn
|
||||
background var(--infoWarnBg)
|
||||
color var(--infoWarnFg)
|
||||
|
||||
&:first-child
|
||||
margin-top 0
|
||||
|
||||
&:last-child
|
||||
margin-bottom 0
|
||||
|
||||
> i
|
||||
margin-right 4px
|
||||
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="ui-input" :class="[{ focused, filled }, styl]">
|
||||
<div class="ui-input" :class="[{ focused, filled, inline }, styl]">
|
||||
<div class="icon" ref="icon"><slot name="icon"></slot></div>
|
||||
<div class="input">
|
||||
<div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
|
||||
@ -41,6 +41,7 @@ import Vue from 'vue';
|
||||
const getPasswordStrength = require('syuilo-password-strength');
|
||||
|
||||
export default Vue.extend({
|
||||
inject: ['horizonGrouped'],
|
||||
props: {
|
||||
value: {
|
||||
required: false
|
||||
@ -72,6 +73,13 @@ export default Vue.extend({
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default(): boolean {
|
||||
return this.horizonGrouped;
|
||||
}
|
||||
},
|
||||
styl: {
|
||||
type: String,
|
||||
required: false,
|
||||
@ -337,4 +345,8 @@ root(fill)
|
||||
&:not(.fill)
|
||||
root(false)
|
||||
|
||||
&.inline
|
||||
display inline-block
|
||||
margin 0
|
||||
|
||||
</style>
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="ui-textarea" :class="{ focused, filled }">
|
||||
<div class="ui-textarea" :class="{ focused, filled, tall }">
|
||||
<div class="input">
|
||||
<span class="label" ref="label"><slot></slot></span>
|
||||
<textarea ref="input"
|
||||
:value="value"
|
||||
:required="required"
|
||||
:readonly="readonly"
|
||||
:pattern="pattern"
|
||||
:autocomplete="autocomplete"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
@focus="focused = true"
|
||||
@blur="focused = false">
|
||||
</textarea>
|
||||
:value="value"
|
||||
:required="required"
|
||||
:readonly="readonly"
|
||||
:pattern="pattern"
|
||||
:autocomplete="autocomplete"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
@focus="focused = true"
|
||||
@blur="focused = false"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="text"><slot name="text"></slot></div>
|
||||
</div>
|
||||
@ -41,7 +41,12 @@ export default Vue.extend({
|
||||
autocomplete: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
tall: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -66,6 +71,9 @@ export default Vue.extend({
|
||||
root(fill)
|
||||
margin 42px 0 32px 0
|
||||
|
||||
&:last-child
|
||||
margin-bottom 0
|
||||
|
||||
> .input
|
||||
padding 12px
|
||||
|
||||
@ -157,6 +165,11 @@ root(fill)
|
||||
left 0 !important
|
||||
transform scale(0.75)
|
||||
|
||||
&.tall
|
||||
> .input
|
||||
> textarea
|
||||
min-height 200px
|
||||
|
||||
.ui-textarea.fill
|
||||
root(true)
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
</div>
|
||||
</header>
|
||||
<div class="text">
|
||||
<misskey-flavored-markdown v-if="note.text" :text="note.text"/>
|
||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="note.emojis"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -222,13 +222,15 @@ class Autocomplete {
|
||||
const trimmedBefore = before.substring(0, before.lastIndexOf(':'));
|
||||
const after = source.substr(caret);
|
||||
|
||||
if (value.startsWith(':')) value = value + ' ';
|
||||
|
||||
// 挿入
|
||||
this.text = trimmedBefore + value + after;
|
||||
|
||||
// キャレットを戻す
|
||||
this.vm.$nextTick(() => {
|
||||
this.textarea.focus();
|
||||
const pos = trimmedBefore.length + 1;
|
||||
const pos = trimmedBefore.length + (value.startsWith(':') ? value.length : 1);
|
||||
this.textarea.setSelectionRange(pos, pos);
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
Vue.filter('bytes', (v, digits = 0) => {
|
||||
if (v == null) return '?';
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (v == 0) return '0';
|
||||
const isMinus = v < 0;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
Vue.filter('number', (n) => {
|
||||
if (n == null) return 'N/A';
|
||||
return n.toLocaleString();
|
||||
});
|
||||
|
@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { version, codename } from '../../../config';
|
||||
import { clientVersion as version, codename } from '../../../config';
|
||||
import define from '../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'version'
|
||||
|
@ -3,6 +3,7 @@ declare const _LANGS_: string;
|
||||
declare const _THEME_COLOR_: string;
|
||||
declare const _COPYRIGHT_: string;
|
||||
declare const _VERSION_: string;
|
||||
declare const _CLIENT_VERSION_: string;
|
||||
declare const _CODENAME_: string;
|
||||
declare const _ENV_: string;
|
||||
|
||||
@ -18,5 +19,6 @@ export const langs = _LANGS_;
|
||||
export const themeColor = _THEME_COLOR_;
|
||||
export const copyright = _COPYRIGHT_;
|
||||
export const version = _VERSION_;
|
||||
export const clientVersion = _CLIENT_VERSION_;
|
||||
export const codename = _CODENAME_;
|
||||
export const env = _ENV_;
|
||||
|
@ -23,8 +23,6 @@ import updateBanner from './api/update-banner';
|
||||
import MkIndex from './views/pages/index.vue';
|
||||
import MkHome from './views/pages/home.vue';
|
||||
import MkDeck from './views/pages/deck/deck.vue';
|
||||
import MkAdmin from './views/pages/admin/admin.vue';
|
||||
import MkStats from './views/pages/stats/stats.vue';
|
||||
import MkUser from './views/pages/user/user.vue';
|
||||
import MkFavorites from './views/pages/favorites.vue';
|
||||
import MkSelectDrive from './views/pages/selectdrive.vue';
|
||||
@ -57,8 +55,6 @@ init(async (launch) => {
|
||||
{ path: '/', name: 'index', component: MkIndex },
|
||||
{ path: '/home', name: 'home', component: MkHome },
|
||||
{ path: '/deck', name: 'deck', component: MkDeck },
|
||||
{ path: '/admin', name: 'admin', component: MkAdmin },
|
||||
{ path: '/stats', name: 'stats', component: MkStats },
|
||||
{ path: '/i/customize-home', component: MkHomeCustomize },
|
||||
{ path: '/i/favorites', component: MkFavorites },
|
||||
{ path: '/i/messaging/:user', component: MkMessagingRoom },
|
||||
|
@ -32,9 +32,21 @@ export default Vue.extend({
|
||||
this.data.forEach(d => d.total = d.notes + d.replies + d.renotes);
|
||||
const peak = Math.max.apply(null, this.data.map(d => d.total));
|
||||
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth();
|
||||
const day = now.getDate();
|
||||
|
||||
let x = 0;
|
||||
this.data.slice().reverse().forEach(d => {
|
||||
this.data.slice().reverse().forEach((d, i) => {
|
||||
d.x = x;
|
||||
|
||||
const date = new Date(year, month, day - i);
|
||||
d.date = {
|
||||
year: date.getFullYear(),
|
||||
month: date.getMonth(),
|
||||
day: date.getDate()
|
||||
};
|
||||
d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay();
|
||||
|
||||
d.v = peak == 0 ? 0 : d.total / (peak / 2);
|
||||
|
@ -43,11 +43,17 @@ export default Vue.extend({
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
(this as any).api('aggregation/users/activity', {
|
||||
(this as any).api('charts/user/notes', {
|
||||
userId: this.user.id,
|
||||
limit: 20 * 7
|
||||
span: 'day',
|
||||
limit: 7 * 20
|
||||
}).then(activity => {
|
||||
this.activity = activity;
|
||||
this.activity = activity.diffs.normal.map((_, i) => ({
|
||||
total: activity.diffs.normal[i] + activity.diffs.reply[i] + activity.diffs.renote[i],
|
||||
notes: activity.diffs.normal[i],
|
||||
replies: activity.diffs.reply[i],
|
||||
renotes: activity.diffs.renote[i]
|
||||
}));
|
||||
this.fetching = false;
|
||||
});
|
||||
},
|
||||
|
@ -1,42 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import { Line } from 'vue-chartjs';
|
||||
import * as mergeOptions from 'merge-options';
|
||||
|
||||
export default Vue.extend({
|
||||
extends: Line,
|
||||
props: {
|
||||
data: {
|
||||
required: true
|
||||
},
|
||||
opts: {
|
||||
required: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data() {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.render();
|
||||
},
|
||||
methods: {
|
||||
render() {
|
||||
this.renderChart(this.data, mergeOptions({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
distribution: 'series'
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
intersect: false,
|
||||
mode: 'index',
|
||||
position: 'nearest'
|
||||
}
|
||||
}, this.opts || {}));
|
||||
}
|
||||
}
|
||||
});
|
@ -1,723 +0,0 @@
|
||||
<template>
|
||||
<div class="gkgckalzgidaygcxnugepioremxvxvpt">
|
||||
<header>
|
||||
<b>%i18n:@title%:</b>
|
||||
<select v-model="chartType">
|
||||
<optgroup label="%i18n:@federation%">
|
||||
<option value="federation-instances">%i18n:@charts.federation-instances%</option>
|
||||
<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@users%">
|
||||
<option value="users">%i18n:@charts.users%</option>
|
||||
<option value="users-total">%i18n:@charts.users-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@notes%">
|
||||
<option value="notes">%i18n:@charts.notes%</option>
|
||||
<option value="local-notes">%i18n:@charts.local-notes%</option>
|
||||
<option value="remote-notes">%i18n:@charts.remote-notes%</option>
|
||||
<option value="notes-total">%i18n:@charts.notes-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@drive%">
|
||||
<option value="drive-files">%i18n:@charts.drive-files%</option>
|
||||
<option value="drive-files-total">%i18n:@charts.drive-files-total%</option>
|
||||
<option value="drive">%i18n:@charts.drive%</option>
|
||||
<option value="drive-total">%i18n:@charts.drive-total%</option>
|
||||
</optgroup>
|
||||
<optgroup label="%i18n:@network%">
|
||||
<option value="network-requests">%i18n:@charts.network-requests%</option>
|
||||
<option value="network-time">%i18n:@charts.network-time%</option>
|
||||
<option value="network-usage">%i18n:@charts.network-usage%</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<div>
|
||||
<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span>
|
||||
</div>
|
||||
</header>
|
||||
<div>
|
||||
<x-chart v-if="chart" :data="data[0]" :opts="data[1]"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XChart from './charts.chart.ts';
|
||||
|
||||
const colors = {
|
||||
local: 'rgb(246, 88, 79)',
|
||||
remote: 'rgb(65, 221, 222)',
|
||||
|
||||
localPlus: 'rgb(52, 178, 118)',
|
||||
remotePlus: 'rgb(158, 255, 209)',
|
||||
localMinus: 'rgb(255, 97, 74)',
|
||||
remoteMinus: 'rgb(255, 149, 134)',
|
||||
|
||||
incoming: 'rgb(52, 178, 118)',
|
||||
outgoing: 'rgb(255, 97, 74)',
|
||||
};
|
||||
|
||||
const rgba = (color: string): string => {
|
||||
return color.replace('rgb', 'rgba').replace(')', ', 0.1)');
|
||||
};
|
||||
|
||||
const limit = 35;
|
||||
|
||||
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
|
||||
const negate = arr => arr.map(x => -x);
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XChart
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
now: null,
|
||||
chart: null,
|
||||
chartType: 'notes',
|
||||
span: 'hour'
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
data(): any {
|
||||
if (this.chart == null) return null;
|
||||
switch (this.chartType) {
|
||||
case 'federation-instances': return this.federationInstancesChart(false);
|
||||
case 'federation-instances-total': return this.federationInstancesChart(true);
|
||||
case 'users': return this.usersChart(false);
|
||||
case 'users-total': return this.usersChart(true);
|
||||
case 'notes': return this.notesChart('combined');
|
||||
case 'local-notes': return this.notesChart('local');
|
||||
case 'remote-notes': return this.notesChart('remote');
|
||||
case 'notes-total': return this.notesTotalChart();
|
||||
case 'drive': return this.driveChart();
|
||||
case 'drive-total': return this.driveTotalChart();
|
||||
case 'drive-files': return this.driveFilesChart();
|
||||
case 'drive-files-total': return this.driveFilesTotalChart();
|
||||
case 'network-requests': return this.networkRequestsChart();
|
||||
case 'network-time': return this.networkTimeChart();
|
||||
case 'network-usage': return this.networkUsageChart();
|
||||
}
|
||||
},
|
||||
|
||||
stats(): any[] {
|
||||
const stats =
|
||||
this.span == 'day' ? this.chart.perDay :
|
||||
this.span == 'hour' ? this.chart.perHour :
|
||||
null;
|
||||
|
||||
return stats;
|
||||
}
|
||||
},
|
||||
|
||||
async created() {
|
||||
this.now = new Date();
|
||||
|
||||
const [perHour, perDay] = await Promise.all([Promise.all([
|
||||
(this as any).api('charts/federation', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/users', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/notes', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/drive', { limit: limit, span: 'hour' }),
|
||||
(this as any).api('charts/network', { limit: limit, span: 'hour' })
|
||||
]), Promise.all([
|
||||
(this as any).api('charts/federation', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/users', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/notes', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/drive', { limit: limit, span: 'day' }),
|
||||
(this as any).api('charts/network', { limit: limit, span: 'day' })
|
||||
])]);
|
||||
|
||||
const chart = {
|
||||
perHour: {
|
||||
federation: perHour[0],
|
||||
users: perHour[1],
|
||||
notes: perHour[2],
|
||||
drive: perHour[3],
|
||||
network: perHour[4]
|
||||
},
|
||||
perDay: {
|
||||
federation: perDay[0],
|
||||
users: perDay[1],
|
||||
notes: perDay[2],
|
||||
drive: perDay[3],
|
||||
network: perDay[4]
|
||||
}
|
||||
};
|
||||
|
||||
this.chart = chart;
|
||||
},
|
||||
|
||||
methods: {
|
||||
getDate(i: number) {
|
||||
const y = this.now.getFullYear();
|
||||
const m = this.now.getMonth();
|
||||
const d = this.now.getDate();
|
||||
const h = this.now.getHours();
|
||||
|
||||
return (
|
||||
this.span == 'day' ? new Date(y, m, d - i) :
|
||||
this.span == 'hour' ? new Date(y, m, d, h - i) :
|
||||
null
|
||||
);
|
||||
},
|
||||
|
||||
format(arr) {
|
||||
return arr.map((v, i) => ({ t: this.getDate(i).getTime(), y: v }));
|
||||
},
|
||||
|
||||
federationInstancesChart(total: boolean): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Instances',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localPlus),
|
||||
borderColor: colors.localPlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(total
|
||||
? this.stats.federation.instance.total
|
||||
: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec)))
|
||||
}]
|
||||
}];
|
||||
},
|
||||
|
||||
notesChart(type: string): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'All',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec))
|
||||
: sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec))
|
||||
)
|
||||
}, {
|
||||
label: 'Renotes',
|
||||
fill: true,
|
||||
backgroundColor: 'rgba(161, 222, 65, 0.1)',
|
||||
borderColor: '#a1de41',
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote)
|
||||
: this.stats.notes[type].diffs.renote
|
||||
)
|
||||
}, {
|
||||
label: 'Replies',
|
||||
fill: true,
|
||||
backgroundColor: 'rgba(247, 121, 108, 0.1)',
|
||||
borderColor: '#f7796c',
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply)
|
||||
: this.stats.notes[type].diffs.reply
|
||||
)
|
||||
}, {
|
||||
label: 'Normal',
|
||||
fill: true,
|
||||
backgroundColor: 'rgba(65, 221, 222, 0.1)',
|
||||
borderColor: '#41ddde',
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(type == 'combined'
|
||||
? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal)
|
||||
: this.stats.notes[type].diffs.normal
|
||||
)
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('number')(value);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
notesTotalChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Combined',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total))
|
||||
}, {
|
||||
label: 'Local',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.local),
|
||||
borderColor: colors.local,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.notes.local.total)
|
||||
}, {
|
||||
label: 'Remote',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remote),
|
||||
borderColor: colors.remote,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.notes.remote.total)
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('number')(value);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
usersChart(total: boolean): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Combined',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(total
|
||||
? sum(this.stats.users.local.total, this.stats.users.remote.total)
|
||||
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
|
||||
)
|
||||
}, {
|
||||
label: 'Local',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.local),
|
||||
borderColor: colors.local,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(total
|
||||
? this.stats.users.local.total
|
||||
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec))
|
||||
)
|
||||
}, {
|
||||
label: 'Remote',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remote),
|
||||
borderColor: colors.remote,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(total
|
||||
? this.stats.users.remote.total
|
||||
: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
|
||||
)
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('number')(value);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
driveChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'All',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(sum(this.stats.drive.local.incSize, negate(this.stats.drive.local.decSize), this.stats.drive.remote.incSize, negate(this.stats.drive.remote.decSize)))
|
||||
}, {
|
||||
label: 'Local +',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localPlus),
|
||||
borderColor: colors.localPlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.local.incSize)
|
||||
}, {
|
||||
label: 'Local -',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localMinus),
|
||||
borderColor: colors.localMinus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(negate(this.stats.drive.local.decSize))
|
||||
}, {
|
||||
label: 'Remote +',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remotePlus),
|
||||
borderColor: colors.remotePlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.remote.incSize)
|
||||
}, {
|
||||
label: 'Remote -',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remoteMinus),
|
||||
borderColor: colors.remoteMinus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(negate(this.stats.drive.remote.decSize))
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('bytes')(value, 1);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
driveTotalChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Combined',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
|
||||
}, {
|
||||
label: 'Local',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.local),
|
||||
borderColor: colors.local,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.local.totalSize)
|
||||
}, {
|
||||
label: 'Remote',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remote),
|
||||
borderColor: colors.remote,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.remote.totalSize)
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('bytes')(value, 1);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
driveFilesChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'All',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(sum(this.stats.drive.local.incCount, negate(this.stats.drive.local.decCount), this.stats.drive.remote.incCount, negate(this.stats.drive.remote.decCount)))
|
||||
}, {
|
||||
label: 'Local +',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localPlus),
|
||||
borderColor: colors.localPlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.local.incCount)
|
||||
}, {
|
||||
label: 'Local -',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localMinus),
|
||||
borderColor: colors.localMinus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(negate(this.stats.drive.local.decCount))
|
||||
}, {
|
||||
label: 'Remote +',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remotePlus),
|
||||
borderColor: colors.remotePlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.remote.incCount)
|
||||
}, {
|
||||
label: 'Remote -',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remoteMinus),
|
||||
borderColor: colors.remoteMinus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(negate(this.stats.drive.remote.decCount))
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('number')(value);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
driveFilesTotalChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Combined',
|
||||
fill: false,
|
||||
borderColor: '#555',
|
||||
borderWidth: 2,
|
||||
borderDash: [4, 4],
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount))
|
||||
}, {
|
||||
label: 'Local',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.local),
|
||||
borderColor: colors.local,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.local.totalCount)
|
||||
}, {
|
||||
label: 'Remote',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.remote),
|
||||
borderColor: colors.remote,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.drive.remote.totalCount)
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('number')(value);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
|
||||
networkRequestsChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Incoming',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localPlus),
|
||||
borderColor: colors.localPlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.network.incomingRequests)
|
||||
}]
|
||||
}];
|
||||
},
|
||||
|
||||
networkTimeChart(): any {
|
||||
const data = [];
|
||||
|
||||
for (let i = 0; i < limit; i++) {
|
||||
data.push(this.stats.network.incomingRequests[i] != 0 ? (this.stats.network.totalTime[i] / this.stats.network.incomingRequests[i]) : 0);
|
||||
}
|
||||
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Avg time (ms)',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.localPlus),
|
||||
borderColor: colors.localPlus,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(data)
|
||||
}]
|
||||
}];
|
||||
},
|
||||
|
||||
networkUsageChart(): any {
|
||||
return [{
|
||||
datasets: [{
|
||||
label: 'Incoming',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.incoming),
|
||||
borderColor: colors.incoming,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.network.incomingBytes)
|
||||
}, {
|
||||
label: 'Outgoing',
|
||||
fill: true,
|
||||
backgroundColor: rgba(colors.outgoing),
|
||||
borderColor: colors.outgoing,
|
||||
borderWidth: 2,
|
||||
pointBackgroundColor: '#fff',
|
||||
lineTension: 0,
|
||||
data: this.format(this.stats.network.outgoingBytes)
|
||||
}]
|
||||
}, {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
callback: value => {
|
||||
return Vue.filter('bytes')(value, 1);
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltipItem, data) => {
|
||||
const label = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.gkgckalzgidaygcxnugepioremxvxvpt
|
||||
padding 32px
|
||||
background #fff
|
||||
box-shadow 0 2px 8px rgba(#000, 0.1)
|
||||
|
||||
*
|
||||
user-select none
|
||||
|
||||
> header
|
||||
display flex
|
||||
margin 0 0 1em 0
|
||||
padding 0 0 8px 0
|
||||
font-size 1em
|
||||
color #555
|
||||
border-bottom solid 1px #eee
|
||||
|
||||
> b
|
||||
margin-right 8px
|
||||
|
||||
> *:last-child
|
||||
margin-left auto
|
||||
|
||||
*
|
||||
&:not(.active)
|
||||
color var(--primary)
|
||||
cursor pointer
|
||||
|
||||
> div
|
||||
> *
|
||||
display block
|
||||
height 350px
|
||||
|
||||
</style>
|
@ -67,12 +67,12 @@ export default Vue.extend({
|
||||
text: '%i18n:@contextmenu.rename%',
|
||||
icon: '%fa:i-cursor%',
|
||||
action: this.rename
|
||||
}/*, null, {
|
||||
}, null, {
|
||||
type: 'item',
|
||||
text: '%i18n:common.delete%',
|
||||
icon: '%fa:R trash-alt%',
|
||||
action: this.deleteFolder
|
||||
}*/], {
|
||||
}], {
|
||||
closed: () => {
|
||||
this.isContextmenuShowing = false;
|
||||
}
|
||||
@ -207,7 +207,9 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
deleteFolder() {
|
||||
alert('not implemented yet');
|
||||
(this as any).api('drive/folders/delete', {
|
||||
folderId: this.folder.id
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ export default Vue.extend({
|
||||
hierarchyFolders: [],
|
||||
selectedFiles: [],
|
||||
uploadings: [],
|
||||
connection: null
|
||||
connection: null,
|
||||
|
||||
/**
|
||||
* ドロップされようとしているか
|
||||
@ -122,6 +122,7 @@ export default Vue.extend({
|
||||
this.connection.on('fileDeleted', this.onStreamDriveFileDeleted);
|
||||
this.connection.on('folderCreated', this.onStreamDriveFolderCreated);
|
||||
this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated);
|
||||
this.connection.on('folderDeleted', this.onStreamDriveFolderDeleted);
|
||||
|
||||
if (this.initFolder) {
|
||||
this.move(this.initFolder);
|
||||
@ -182,6 +183,10 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
onStreamDriveFolderDeleted(folderId) {
|
||||
this.removeFolder(folderId);
|
||||
},
|
||||
|
||||
onChangeUploaderUploads(uploads) {
|
||||
this.uploadings = uploads;
|
||||
},
|
||||
|
@ -40,8 +40,8 @@ export default Vue.extend({
|
||||
|
||||
mounted() {
|
||||
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||
this.connection.on('follow', this.onFollow);
|
||||
this.connection.on('unfollow', this.onUnfollow);
|
||||
this.connection.on('follow', this.onFollowChange);
|
||||
this.connection.on('unfollow', this.onFollowChange);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
@ -49,17 +49,11 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
methods: {
|
||||
onFollow(user) {
|
||||
if (user.id == this.u.id) {
|
||||
this.u.isFollowing = user.isFollowing;
|
||||
this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
|
||||
}
|
||||
},
|
||||
|
||||
onUnfollow(user) {
|
||||
onFollowChange(user) {
|
||||
if (user.id == this.u.id) {
|
||||
this.u.isFollowing = user.isFollowing;
|
||||
this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
<div class="text">
|
||||
<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
||||
<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :customEmojis="p.emojis" />
|
||||
</div>
|
||||
<div class="files" v-if="p.files.length > 0">
|
||||
<mk-media-list :media-list="p.files" :raw="true"/>
|
||||
|
@ -34,7 +34,7 @@
|
||||
<div class="text">
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
||||
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
|
||||
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
|
||||
<a class="rp" v-if="appearNote.renote">RN:</a>
|
||||
</div>
|
||||
<div class="files" v-if="appearNote.files.length > 0">
|
||||
|
@ -4,10 +4,7 @@
|
||||
|
||||
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
||||
|
||||
<div v-if="!fetching && requestInitPromise != null" class="error">
|
||||
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
|
||||
<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>
|
||||
</div>
|
||||
<mk-error v-if="!fetching && requestInitPromise != null" @retry="resolveInitPromise"/>
|
||||
|
||||
<div class="placeholder" v-if="fetching">
|
||||
<template v-for="i in 10">
|
||||
@ -215,16 +212,6 @@ export default Vue.extend({
|
||||
> *
|
||||
transition transform .3s ease, opacity .3s ease
|
||||
|
||||
> .error
|
||||
max-width 300px
|
||||
margin 0 auto
|
||||
padding 32px
|
||||
text-align center
|
||||
color var(--text)
|
||||
|
||||
> p
|
||||
margin 0 0 8px 0
|
||||
|
||||
> .placeholder
|
||||
padding 32px
|
||||
opacity 0.3
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="2fa">
|
||||
<p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p>
|
||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
|
||||
<p style="margin-top:0;">%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p>
|
||||
<ui-info warn>%i18n:@caution%</ui-info>
|
||||
<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">%i18n:@register%</ui-button></p>
|
||||
<template v-if="$store.state.i.twoFactorEnabled">
|
||||
<p>%i18n:@already-registered%</p>
|
||||
@ -72,9 +72,3 @@ export default Vue.extend({
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.2fa
|
||||
color #4a535a
|
||||
|
||||
</style>
|
||||
|
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<div class="root api">
|
||||
<ui-input :value="$store.state.i.token" readonly>
|
||||
<span>%i18n:@token%</span>
|
||||
</ui-input>
|
||||
<p>%i18n:@intro%</p>
|
||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
|
||||
<p>%i18n:@regeneration-of-token%</p>
|
||||
<ui-button @click="regenerateToken">%i18n:@regenerate-token%</ui-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
methods: {
|
||||
regenerateToken() {
|
||||
(this as any).apis.input({
|
||||
title: '%i18n:@enter-password%',
|
||||
type: 'password'
|
||||
}).then(password => {
|
||||
(this as any).api('i/regenerate_token', {
|
||||
password: password
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.root.api
|
||||
code
|
||||
display inline-block
|
||||
padding 4px 6px
|
||||
color #555
|
||||
background #eee
|
||||
border-radius 2px
|
||||
</style>
|
@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="none ui info" v-if="!fetching && apps.length == 0">
|
||||
<p>%fa:info-circle%%i18n:@no-apps%</p>
|
||||
</div>
|
||||
<ui-info v-if="!fetching && apps.length == 0">%i18n:@no-apps%</ui-info>
|
||||
<div class="apps" v-if="apps.length != 0">
|
||||
<div v-for="app in apps">
|
||||
<p><b>{{ app.name }}</b></p>
|
||||
|
@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="none ui info" v-if="!fetching && users.length == 0">
|
||||
<p>%fa:info-circle%%i18n:@no-users%</p>
|
||||
</div>
|
||||
<div class="users" v-if="users.length != 0">
|
||||
<div v-for="user in users" :key="user.id">
|
||||
<p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
users: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
(this as any).api('mute/list').then(x => {
|
||||
this.users = x.users;
|
||||
this.fetching = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
@ -7,7 +7,7 @@
|
||||
<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p>
|
||||
<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:common.drive%</p>
|
||||
<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p>
|
||||
<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:@mute%</p>
|
||||
<p :class="{ active: page == 'muteAndBlock' }" @mousedown="page = 'muteAndBlock'">%fa:ban .fw%%i18n:@mute-and-block%</p>
|
||||
<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p>
|
||||
<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p>
|
||||
<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p>
|
||||
@ -23,6 +23,13 @@
|
||||
<mk-twitter-setting/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%fa:B github% %i18n:@github%</div>
|
||||
<section>
|
||||
<mk-github-setting/>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
|
||||
<ui-card class="theme" v-show="page == 'theme'">
|
||||
@ -200,12 +207,9 @@
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="mute" v-show="page == 'mute'">
|
||||
<div slot="title">%fa:ban% %i18n:@mute%</div>
|
||||
<section>
|
||||
<x-mute/>
|
||||
</section>
|
||||
</ui-card>
|
||||
<div class="muteAndBlock" v-show="page == 'muteAndBlock'">
|
||||
<mk-mute-and-block/>
|
||||
</div>
|
||||
|
||||
<ui-card class="apps" v-show="page == 'apps'">
|
||||
<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div>
|
||||
@ -217,7 +221,7 @@
|
||||
<ui-card class="password" v-show="page == 'security'">
|
||||
<div slot="title">%fa:unlock-alt% %i18n:@password%</div>
|
||||
<section>
|
||||
<x-password/>
|
||||
<mk-password-settings/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
@ -235,12 +239,9 @@
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="api" v-show="page == 'api'">
|
||||
<div slot="title">%fa:key% API</div>
|
||||
<section class="fit-top">
|
||||
<x-api/>
|
||||
</section>
|
||||
</ui-card>
|
||||
<div class="api" v-show="page == 'api'">
|
||||
<mk-api-settings/>
|
||||
</div>
|
||||
|
||||
<ui-card class="other" v-show="page == 'other'">
|
||||
<div slot="title">%fa:info-circle% %i18n:@about%</div>
|
||||
@ -292,22 +293,16 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XMute from './settings.mute.vue';
|
||||
import XPassword from './settings.password.vue';
|
||||
import X2fa from './settings.2fa.vue';
|
||||
import XApi from './settings.api.vue';
|
||||
import XApps from './settings.apps.vue';
|
||||
import XSignins from './settings.signins.vue';
|
||||
import XTags from './settings.tags.vue';
|
||||
import { url, langs, version } from '../../../config';
|
||||
import { url, langs, clientVersion as version } from '../../../config';
|
||||
import checkForUpdate from '../../../common/scripts/check-for-update';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XMute,
|
||||
XPassword,
|
||||
X2fa,
|
||||
XApi,
|
||||
XApps,
|
||||
XSignins,
|
||||
XTags
|
||||
|
@ -4,7 +4,7 @@
|
||||
<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span>
|
||||
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
|
||||
<a class="reply" v-if="note.replyId">%fa:reply%</a>
|
||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
|
||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i" :customEmojis="note.emojis"/>
|
||||
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a>
|
||||
</div>
|
||||
<details v-if="note.files.length > 0">
|
||||
|
@ -31,7 +31,7 @@
|
||||
<p>%fa:cog%<span>%i18n:@settings%</span>%fa:angle-right%</p>
|
||||
</li>
|
||||
<li v-if="$store.state.i.isAdmin">
|
||||
<router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link>
|
||||
<a href="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
|
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<div class="qldxjjsrseehkusjuoooapmsprvfrxyl mk-admin-card">
|
||||
<header>%i18n:@announcements%</header>
|
||||
<textarea v-model="broadcasts" placeholder='[ { "title": "Title1", "text": "Text1" }, { "title": "Title2", "text": "Text2" } ]'></textarea>
|
||||
<button class="ui" @click="save">%i18n:@save%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
broadcasts: '',
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.broadcasts = JSON.stringify(meta.broadcasts, null, ' ');
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
let json;
|
||||
|
||||
try {
|
||||
json = JSON.parse(this.broadcasts);
|
||||
} catch (e) {
|
||||
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
return;
|
||||
}
|
||||
|
||||
(this as any).api('admin/update-meta', {
|
||||
broadcasts: json
|
||||
}).then(() => {
|
||||
(this as any).os.apis.dialog({ text: `Saved` });
|
||||
}.catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.qldxjjsrseehkusjuoooapmsprvfrxyl
|
||||
textarea
|
||||
width 100%
|
||||
min-height 300px
|
||||
|
||||
</style>
|
@ -1,137 +0,0 @@
|
||||
<template>
|
||||
<div class="zyknedwtlthezamcjlolyusmipqmjgxz">
|
||||
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
|
||||
<defs>
|
||||
<linearGradient :id="cpuGradientId" x1="0" x2="0" y1="1" y2="0">
|
||||
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
|
||||
<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
|
||||
</linearGradient>
|
||||
<mask :id="cpuMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
|
||||
<polygon
|
||||
:points="cpuPolygonPoints"
|
||||
fill="#fff"
|
||||
fill-opacity="0.5"/>
|
||||
<polyline
|
||||
:points="cpuPolylinePoints"
|
||||
fill="none"
|
||||
stroke="#fff"
|
||||
stroke-width="1"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<rect
|
||||
x="0" y="0"
|
||||
:width="viewBoxX" :height="viewBoxY"
|
||||
:style="`stroke: none; fill: url(#${ cpuGradientId }); mask: url(#${ cpuMaskId })`"/>
|
||||
<text x="1" y="12">CPU <tspan>{{ cpuP }}%</tspan></text>
|
||||
</svg>
|
||||
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`">
|
||||
<defs>
|
||||
<linearGradient :id="memGradientId" x1="0" x2="0" y1="1" y2="0">
|
||||
<stop offset="0%" stop-color="hsl(180, 80%, 70%)"></stop>
|
||||
<stop offset="100%" stop-color="hsl(0, 80%, 70%)"></stop>
|
||||
</linearGradient>
|
||||
<mask :id="memMaskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY">
|
||||
<polygon
|
||||
:points="memPolygonPoints"
|
||||
fill="#fff"
|
||||
fill-opacity="0.5"/>
|
||||
<polyline
|
||||
:points="memPolylinePoints"
|
||||
fill="none"
|
||||
stroke="#fff"
|
||||
stroke-width="1"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<rect
|
||||
x="0" y="0"
|
||||
:width="viewBoxX" :height="viewBoxY"
|
||||
:style="`stroke: none; fill: url(#${ memGradientId }); mask: url(#${ memMaskId })`"/>
|
||||
<text x="1" y="12">MEM <tspan>{{ memP }}%</tspan></text>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['connection'],
|
||||
data() {
|
||||
return {
|
||||
viewBoxX: 200,
|
||||
viewBoxY: 70,
|
||||
stats: [],
|
||||
cpuGradientId: uuid(),
|
||||
cpuMaskId: uuid(),
|
||||
memGradientId: uuid(),
|
||||
memMaskId: uuid(),
|
||||
cpuPolylinePoints: '',
|
||||
memPolylinePoints: '',
|
||||
cpuPolygonPoints: '',
|
||||
memPolygonPoints: '',
|
||||
cpuP: '',
|
||||
memP: ''
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.connection.on('stats', this.onStats);
|
||||
this.connection.on('statsLog', this.onStatsLog);
|
||||
this.connection.send('requestLog', {
|
||||
id: Math.random().toString().substr(2, 8),
|
||||
length: 200
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.connection.off('stats', this.onStats);
|
||||
this.connection.off('statsLog', this.onStatsLog);
|
||||
},
|
||||
methods: {
|
||||
onStats(stats) {
|
||||
this.stats.push(stats);
|
||||
if (this.stats.length > 200) this.stats.shift();
|
||||
|
||||
const cpuPolylinePoints = this.stats.map((s, i) => [this.viewBoxX - ((this.stats.length - 1) - i), (1 - s.cpu_usage) * this.viewBoxY]);
|
||||
const memPolylinePoints = this.stats.map((s, i) => [this.viewBoxX - ((this.stats.length - 1) - i), (1 - (s.mem.used / s.mem.total)) * this.viewBoxY]);
|
||||
this.cpuPolylinePoints = cpuPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
|
||||
this.memPolylinePoints = memPolylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' ');
|
||||
|
||||
this.cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${this.viewBoxY} ${this.cpuPolylinePoints} ${this.viewBoxX},${this.viewBoxY}`;
|
||||
this.memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${this.viewBoxY} ${this.memPolylinePoints} ${this.viewBoxX},${this.viewBoxY}`;
|
||||
|
||||
this.cpuP = (stats.cpu_usage * 100).toFixed(0);
|
||||
this.memP = (stats.mem.used / stats.mem.total * 100).toFixed(0);
|
||||
},
|
||||
onStatsLog(statsLog) {
|
||||
statsLog.reverse().forEach(stats => this.onStats(stats));
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.zyknedwtlthezamcjlolyusmipqmjgxz
|
||||
> svg
|
||||
display block
|
||||
width 50%
|
||||
float left
|
||||
|
||||
&:first-child
|
||||
padding-right 5px
|
||||
|
||||
&:last-child
|
||||
padding-left 5px
|
||||
|
||||
> text
|
||||
font-size 10px
|
||||
fill var(--chartCaption)
|
||||
|
||||
> tspan
|
||||
opacity 0.5
|
||||
|
||||
&:after
|
||||
content ""
|
||||
display block
|
||||
clear both
|
||||
|
||||
</style>
|
@ -1,135 +0,0 @@
|
||||
<template>
|
||||
<div class="obdskegsannmntldydackcpzezagxqfy mk-admin-card">
|
||||
<header>%i18n:@dashboard%</header>
|
||||
|
||||
<div v-if="stats" class="stats">
|
||||
<div><b>%fa:user% {{ stats.originalUsersCount | number }}</b><span>%i18n:@original-users%</span></div>
|
||||
<div><span>%fa:user% {{ stats.usersCount | number }}</span><span>%i18n:@all-users%</span></div>
|
||||
<div><b>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div>
|
||||
<div><span>%fa:pencil-alt% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div>
|
||||
</div>
|
||||
|
||||
<div class="cpu-memory">
|
||||
<x-cpu-memory :connection="connection"/>
|
||||
</div>
|
||||
|
||||
<div v-if="this.$store.state.i && this.$store.state.i.isAdmin" class="form">
|
||||
<div>
|
||||
<label>
|
||||
<p>%i18n:@banner-url%</p>
|
||||
<input v-model="bannerUrl">
|
||||
</label>
|
||||
<button class="ui" @click="updateMeta">%i18n:@save%</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" v-model="disableRegistration" @change="updateMeta">
|
||||
<span>%i18n:@disableRegistration%</span>
|
||||
</label>
|
||||
<button class="ui" @click="invite">%i18n:@invite%</button>
|
||||
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" v-model="disableLocalTimeline" @change="updateMeta">
|
||||
<span>%i18n:@disableLocalTimeline%</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import XCpuMemory from "./admin.cpu-memory.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XCpuMemory
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
stats: null,
|
||||
disableRegistration: false,
|
||||
disableLocalTimeline: false,
|
||||
bannerUrl: null,
|
||||
inviteCode: null,
|
||||
connection: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.connection = (this as any).os.stream.useSharedConnection('serverStats');
|
||||
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.disableRegistration = meta.disableRegistration;
|
||||
this.disableLocalTimeline = meta.disableLocalTimeline;
|
||||
this.bannerUrl = meta.bannerUrl;
|
||||
});
|
||||
|
||||
(this as any).api('stats').then(stats => {
|
||||
this.stats = stats;
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.connection.dispose();
|
||||
},
|
||||
methods: {
|
||||
invite() {
|
||||
(this as any).api('admin/invite').then(x => {
|
||||
this.inviteCode = x.code;
|
||||
}).catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
},
|
||||
updateMeta() {
|
||||
(this as any).api('admin/update-meta', {
|
||||
disableRegistration: this.disableRegistration,
|
||||
disableLocalTimeline: this.disableLocalTimeline,
|
||||
bannerUrl: this.bannerUrl
|
||||
}).then(() => {
|
||||
(this as any).os.apis.dialog({ text: `Saved` });
|
||||
}).catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed ${e}` });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
|
||||
.obdskegsannmntldydackcpzezagxqfy
|
||||
> .stats
|
||||
display flex
|
||||
justify-content center
|
||||
margin-bottom 16px
|
||||
padding 16px
|
||||
border solid 1px #eee
|
||||
border-radius 8px
|
||||
|
||||
> div
|
||||
flex 1
|
||||
text-align center
|
||||
|
||||
> *:first-child
|
||||
display block
|
||||
color var(--primary)
|
||||
|
||||
> *:last-child
|
||||
font-size 70%
|
||||
|
||||
> .cpu-memory
|
||||
margin-bottom 16px
|
||||
padding 16px
|
||||
border solid 1px #eee
|
||||
border-radius: 8px
|
||||
|
||||
> .form
|
||||
> div
|
||||
padding 16px
|
||||
border-bottom solid 1px #eee
|
||||
|
||||
</style>
|
@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div class="mk-admin-card">
|
||||
<header>%i18n:@suspend-user%</header>
|
||||
<input v-model="username" type="text" class="ui"/>
|
||||
<button class="ui" @click="suspendUser" :disabled="suspending">%i18n:@suspend%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import parseAcct from "../../../../../../misc/acct/parse";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
suspending: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async suspendUser() {
|
||||
this.suspending = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api(
|
||||
"users/show",
|
||||
parseAcct(this.username)
|
||||
);
|
||||
|
||||
await (this as any).os.api("admin/suspend-user", {
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
(this as any).os.apis.dialog({ text: "%i18n:@suspended%" });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.suspending = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
|
||||
header
|
||||
margin 10px 0
|
||||
|
||||
|
||||
button
|
||||
margin 16px 0
|
||||
|
||||
</style>
|
@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="mk-admin-card">
|
||||
<header>%i18n:@unsuspend-user%</header>
|
||||
<input v-model="username" type="text" class="ui"/>
|
||||
<button class="ui" @click="unsuspendUser" :disabled="unsuspending">%i18n:@unsuspend%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import parseAcct from "../../../../../../misc/acct/parse";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
unsuspending: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async unsuspendUser() {
|
||||
this.unsuspending = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api(
|
||||
"users/show",
|
||||
parseAcct(this.username)
|
||||
);
|
||||
|
||||
await (this as any).os.api("admin/unsuspend-user", {
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
(this as any).os.apis.dialog({ text: "%i18n:@unsuspended%" });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.unsuspending = false;
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
|
||||
header
|
||||
margin 10px 0
|
||||
|
||||
|
||||
button
|
||||
margin 16px 0
|
||||
|
||||
</style>
|
@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div class="mk-admin-card">
|
||||
<header>%i18n:@unverify-user%</header>
|
||||
<input v-model="username" type="text" class="ui"/>
|
||||
<button class="ui" @click="unverifyUser" :disabled="unverifying">%i18n:@unverify%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import parseAcct from "../../../../../../misc/acct/parse";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
unverifying: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async unverifyUser() {
|
||||
this.unverifying = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api(
|
||||
"users/show",
|
||||
parseAcct(this.username)
|
||||
);
|
||||
|
||||
await (this as any).os.api("admin/unverify-user", {
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
(this as any).os.apis.dialog({ text: "%i18n:@unverified%" });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.unverifying = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
|
||||
header
|
||||
margin 10px 0
|
||||
|
||||
|
||||
button
|
||||
margin 16px 0
|
||||
|
||||
</style>
|
@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div class="mk-admin-card">
|
||||
<header>%i18n:@verify-user%</header>
|
||||
<input v-model="username" type="text" class="ui"/>
|
||||
<button class="ui" @click="verifyUser" :disabled="verifying">%i18n:@verify%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import parseAcct from "../../../../../../misc/acct/parse";
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
verifying: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async verifyUser() {
|
||||
this.verifying = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await (this as any).os.api(
|
||||
"users/show",
|
||||
parseAcct(this.username)
|
||||
);
|
||||
|
||||
await (this as any).os.api("admin/verify-user", {
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
(this as any).os.apis.dialog({ text: "%i18n:@verified%" });
|
||||
};
|
||||
|
||||
await process().catch(e => {
|
||||
(this as any).os.apis.dialog({ text: `Failed: ${e}` });
|
||||
});
|
||||
|
||||
this.verifying = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
|
||||
header
|
||||
margin 10px 0
|
||||
|
||||
|
||||
button
|
||||
margin 16px 0
|
||||
|
||||
</style>
|
@ -1,140 +0,0 @@
|
||||
<template>
|
||||
<div class="mk-admin">
|
||||
<nav>
|
||||
<ul>
|
||||
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
|
||||
|
||||
<li v-if="this.$store.state.i && this.$store.state.i.isAdmin"
|
||||
@click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
|
||||
|
||||
<li v-if="this.$store.state.i && this.$store.state.i.isAdmin"
|
||||
@click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
|
||||
|
||||
<li v-if="this.$store.state.i && this.$store.state.i.isAdmin"
|
||||
@click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li>
|
||||
|
||||
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> -->
|
||||
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<div v-show="page == 'dashboard'">
|
||||
<x-dashboard/>
|
||||
<x-charts/>
|
||||
</div>
|
||||
<div v-show="page == 'announcements'">
|
||||
<x-announcements/>
|
||||
</div>
|
||||
<div v-show="page == 'hashtags'">
|
||||
<x-hashtags/>
|
||||
</div>
|
||||
<div v-if="page == 'users'">
|
||||
<x-suspend-user/>
|
||||
<x-unsuspend-user/>
|
||||
<x-verify-user/>
|
||||
<x-unverify-user/>
|
||||
</div>
|
||||
<div v-if="page == 'drive'"></div>
|
||||
<div v-if="page == 'update'"></div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import XDashboard from "./admin.dashboard.vue";
|
||||
import XAnnouncements from "./admin.announcements.vue";
|
||||
import XHashtags from "./admin.hashtags.vue";
|
||||
import XSuspendUser from "./admin.suspend-user.vue";
|
||||
import XUnsuspendUser from "./admin.unsuspend-user.vue";
|
||||
import XVerifyUser from "./admin.verify-user.vue";
|
||||
import XUnverifyUser from "./admin.unverify-user.vue";
|
||||
import XCharts from "../../components/charts.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XDashboard,
|
||||
XAnnouncements,
|
||||
XHashtags,
|
||||
XSuspendUser,
|
||||
XUnsuspendUser,
|
||||
XVerifyUser,
|
||||
XUnverifyUser,
|
||||
XCharts
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
page: 'dashboard'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
nav(page: string) {
|
||||
this.page = page;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
||||
|
||||
.mk-admin
|
||||
display flex
|
||||
height 100%
|
||||
margin 32px
|
||||
|
||||
> nav
|
||||
flex 0 0 250px
|
||||
width 100%
|
||||
height 100%
|
||||
padding 16px 0 0 0
|
||||
overflow auto
|
||||
border-right solid 1px #ddd
|
||||
|
||||
> ul
|
||||
list-style none
|
||||
|
||||
> li
|
||||
display block
|
||||
padding 10px 16px
|
||||
margin 0
|
||||
color #666
|
||||
cursor pointer
|
||||
user-select none
|
||||
transition margin-left 0.2s ease
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
|
||||
&:hover
|
||||
color #555
|
||||
|
||||
&.active
|
||||
margin-left 8px
|
||||
color var(--primary) !important
|
||||
|
||||
> main
|
||||
width 100%
|
||||
padding 16px 32px
|
||||
|
||||
> div
|
||||
> div
|
||||
max-width 800px
|
||||
|
||||
.mk-admin-card
|
||||
padding 32px
|
||||
background #fff
|
||||
box-shadow 0 2px 8px rgba(#000, 0.1)
|
||||
|
||||
&:not(:last-child)
|
||||
margin-bottom 16px
|
||||
|
||||
> header
|
||||
margin 0 0 1em 0
|
||||
padding 0 0 8px 0
|
||||
font-size 1em
|
||||
color #555
|
||||
border-bottom solid 1px #eee
|
||||
|
||||
</style>
|
@ -287,7 +287,7 @@ export default Vue.extend({
|
||||
|
||||
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||
|
||||
if (!this.dragging) this.draghover = true;
|
||||
if (!this.dragging && isDeckColumn) this.draghover = true;
|
||||
},
|
||||
|
||||
onDragleave() {
|
||||
|
@ -8,10 +8,7 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="!fetching && requestInitPromise != null" class="error">
|
||||
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
|
||||
<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>
|
||||
</div>
|
||||
<mk-error v-if="!fetching && requestInitPromise != null" @retry="resolveInitPromise"/>
|
||||
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!--<transition-group name="mk-notes" class="transition" ref="notes">-->
|
||||
@ -221,13 +218,6 @@ export default Vue.extend({
|
||||
> *
|
||||
transition transform .3s ease, opacity .3s ease
|
||||
|
||||
> .error
|
||||
max-width 300px
|
||||
margin 0 auto
|
||||
padding 16px
|
||||
text-align center
|
||||
color var(--text)
|
||||
|
||||
> .placeholder
|
||||
padding 16px
|
||||
opacity 0.3
|
||||
|
@ -1,65 +0,0 @@
|
||||
<template>
|
||||
<div class="tcrwdhwpuxrwmcttxjcsehgpagpstqey">
|
||||
<div v-if="stats" class="stats">
|
||||
<div><b>%fa:user% {{ stats.originalUsersCount | number }}</b><span>%i18n:@original-users%</span></div>
|
||||
<div><span>%fa:user% {{ stats.usersCount | number }}</span><span>%i18n:@all-users%</span></div>
|
||||
<div><b>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</b><span>%i18n:@original-notes%</span></div>
|
||||
<div><span>%fa:pencil-alt% {{ stats.notesCount | number }}</span><span>%i18n:@all-notes%</span></div>
|
||||
</div>
|
||||
<div>
|
||||
<x-charts/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import XCharts from "../../components/charts.vue";
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XCharts
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
stats: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
(this as any).api('stats').then(stats => {
|
||||
this.stats = stats;
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
||||
|
||||
.tcrwdhwpuxrwmcttxjcsehgpagpstqey
|
||||
width 100%
|
||||
padding 16px
|
||||
|
||||
> .stats
|
||||
display flex
|
||||
justify-content center
|
||||
margin 0 auto 16px auto
|
||||
padding 32px
|
||||
background #fff
|
||||
box-shadow 0 2px 8px rgba(#000, 0.1)
|
||||
|
||||
> div
|
||||
flex 1
|
||||
text-align center
|
||||
|
||||
> *:first-child
|
||||
display block
|
||||
color var(--primary)
|
||||
|
||||
> *:last-child
|
||||
font-size 70%
|
||||
|
||||
> div
|
||||
max-width 950px
|
||||
margin 0 auto
|
||||
</style>
|
26
src/client/app/desktop/views/pages/user/user.github.vue
Normal file
26
src/client/app/desktop/views/pages/user/user.github.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="aqooishiizumijmihokohinatamihoaz">
|
||||
<span>%fa:B github%<a :href="`https://github.com/${user.github.login}`" target="_blank">@{{ user.github.login }}</a></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['user']
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.aqooishiizumijmihokohinatamihoaz
|
||||
padding 32px
|
||||
background #171515
|
||||
border-radius 6px
|
||||
color #fff
|
||||
|
||||
a
|
||||
margin-left 8px
|
||||
color #fff
|
||||
|
||||
</style>
|
@ -11,7 +11,11 @@
|
||||
<div class="action-form">
|
||||
<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id">
|
||||
<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
|
||||
<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
|
||||
<span v-else>%fa:eye-slash% %i18n:@mute%</span>
|
||||
</ui-button>
|
||||
<ui-button @click="user.isBlocking ? unblock() : block()" v-if="$store.state.i.id != user.id">
|
||||
<span v-if="user.isBlocking">%fa:user% %i18n:@unblock%</span>
|
||||
<span v-else>%fa:user-slash% %i18n:@block%</span>
|
||||
</ui-button>
|
||||
<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button>
|
||||
</div>
|
||||
@ -66,6 +70,27 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
|
||||
block() {
|
||||
if (!window.confirm('%i18n:@block-confirm%')) return;
|
||||
(this as any).api('blocking/create', {
|
||||
userId: this.user.id
|
||||
}).then(() => {
|
||||
this.user.isBlocking = true;
|
||||
}, () => {
|
||||
alert('error');
|
||||
});
|
||||
},
|
||||
|
||||
unblock() {
|
||||
(this as any).api('blocking/delete', {
|
||||
userId: this.user.id
|
||||
}).then(() => {
|
||||
this.user.isBlocking = false;
|
||||
}, () => {
|
||||
alert('error');
|
||||
});
|
||||
},
|
||||
|
||||
list() {
|
||||
const w = (this as any).os.new(MkUserListsWindow);
|
||||
w.$once('choosen', async list => {
|
||||
@ -114,7 +139,6 @@ export default Vue.extend({
|
||||
> .action-form
|
||||
padding 16px
|
||||
text-align center
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
|
||||
> *
|
||||
width 100%
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user