Merge branch 'develop' of https://codeberg.org/calckey/calckey into feat/module-player
This commit is contained in:
commit
c788adb3e5
67 changed files with 2101 additions and 1231 deletions
13
.config/LICENSE
Normal file
13
.config/LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright 2023 Calckey
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -25,6 +25,7 @@ coverage
|
|||
!/.config/devenv.yml
|
||||
!/.config/docker_example.env
|
||||
!/.config/helm_values_example.yml
|
||||
!/.config/LICENSE
|
||||
|
||||
#docker dev config
|
||||
/dev/docker-compose.yml
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
- 👍 also triggers generic like/favorite
|
||||
- [Add additional background for acrylic popups if backdrop-filter is unsupported](https://github.com/misskey-dev/misskey/pull/8671)
|
||||
- [Add parameters to MFM rotate](https://github.com/misskey-dev/misskey/pull/8549)
|
||||
- Many changes from [Foundkey](https://akkoma.dev/FoundKeyGang/Foundkey)
|
||||
- Many changes from [FoundKey](https://akkoma.dev/FoundKeyGang/FoundKey)
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/0ece67b04c3f0365057624c1068808276ccab981: refactor pages/auth.form.vue to composition API
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/4bc9610d8bf5af736b5e89e4782395705de45d7d: remove unnecessary joins
|
||||
- https://akkoma.dev/FoundKeyGang/FoundKey/commit/9ee609d70082f7a6dc119a5d83c0e7c5e1208676: enhance privacy of notes
|
||||
|
|
|
@ -2704,7 +2704,7 @@ Co-committed-by: naskya <naskya@noreply.codeberg.org>
|
|||
|
||||
Passwords will be automatically re-hashed on sign-in. All new password hashes will be argon2 by default. This uses argon2id and is not configurable. In the very unlikely case someone has more specific needs, a fork is recommended. ChangeLog: Added Co-authored-by: Chloe Kudryavtsev <code@toast.bunkerlabs.net>
|
||||
|
||||
Breaks Calckey -> Misskey migration, but fixes Foundkey -> Calckey migration
|
||||
Breaks Calckey -> Misskey migration, but fixes FoundKey -> Calckey migration
|
||||
|
||||
- Add argon
|
||||
|
||||
|
|
29
COPYING
29
COPYING
|
@ -1,15 +1,24 @@
|
|||
Unless otherwise stated this repository is
|
||||
Copyright © 2014-2022 syuilo and contributers
|
||||
Copyright © 2022 thatonecalculator and contributers
|
||||
Unless specified otherwise, the entirety of this repository is subject to the following:
|
||||
Copyright © 2014-2023 syuilo and contributors
|
||||
Copyright © 2022-2023 Kainoa Kanter and contributors
|
||||
|
||||
And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE.
|
||||
|
||||
---
|
||||
|
||||
Calckey includes several third-party Open-Source softwares.
|
||||
These specific configuration directories:
|
||||
|
||||
Emoji keywords for Unicode 11 and below by Mu-An Chiou
|
||||
License: MIT
|
||||
https://github.com/muan/emojilib/blob/master/LICENSE
|
||||
- .config/
|
||||
- custom/assets/
|
||||
|
||||
and their contents are
|
||||
Copyright © 2022-2023 Kainoa Kanter and contributors
|
||||
|
||||
And are distributed under The Apache License, Version 2.0, you should have received a copy of the license file as LICENSE in each specified directory.
|
||||
|
||||
---
|
||||
|
||||
Calckey includes several third-party open-source softwares and software libraries.
|
||||
|
||||
RsaSignature2017 implementation by Transmute Industries Inc
|
||||
License: MIT
|
||||
|
@ -23,6 +32,6 @@ Chiptune2.js by Simon Gündling
|
|||
License: MIT
|
||||
https://github.com/deskjet/chiptune2.js#license
|
||||
|
||||
libopenmpt (as part of openmpt) by OpenMPT
|
||||
License: BSD 3-Clause
|
||||
https://github.com/OpenMPT/openmpt/blob/master/LICENSE
|
||||
Licenses for all softwares and software libraries installed via the Node Package Manager ("npm") can be found by running the following shell command in the root directory of this repository:
|
||||
|
||||
pnpm licenses list
|
||||
|
|
12
README.md
12
README.md
|
@ -72,6 +72,14 @@
|
|||
|
||||
# 🌠 Getting started
|
||||
|
||||
Want to just join a Calckey server? View the list here, pick one, and join:
|
||||
|
||||
### https://calckey.org/join
|
||||
|
||||
---
|
||||
|
||||
Want to make your own? Keep reading!
|
||||
|
||||
This guide will work for both **starting from scratch** and **migrating from Misskey**.
|
||||
|
||||
## 🔰 Easy installers
|
||||
|
@ -208,9 +216,9 @@ Please don't use ElasticSearch unless you already have an ElasticSearch setup an
|
|||
- Edit `.config/default.yml`, making sure to fill out required fields.
|
||||
- Also copy and edit `.config/docker_example.env` to `.config/docker.env` if you're using Docker.
|
||||
|
||||
## 🚚 Migrating from Misskey to Calckey
|
||||
## 🚚 Migrating from Misskey/FoundKey to Calckey
|
||||
|
||||
For migrating from Misskey v13, Misskey v12, and Foundkey, read [this document](https://codeberg.org/calckey/calckey/src/branch/develop/docs/migrate.md).
|
||||
For migrating from Misskey v13, Misskey v12, and FoundKey, read [this document](https://codeberg.org/calckey/calckey/src/branch/develop/docs/migrate.md).
|
||||
|
||||
## 🌐 Web proxy
|
||||
|
||||
|
|
13
custom/assets/LICENSE
Normal file
13
custom/assets/LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
Copyright 2023 Calckey
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,10 +1,11 @@
|
|||
# 🚚 Migrating from Misskey to Calckey
|
||||
# 🚚 Migrating from Misskey/FoundKey to Calckey
|
||||
|
||||
The following procedure may not work depending on your environment and version of Misskey.
|
||||
All the guides below assume you're starting in the root of the repo directory.
|
||||
|
||||
**Make sure you**
|
||||
- **stopped all master and worker processes of Misskey.**
|
||||
- **have backups of the database before performing any commands.**
|
||||
### Before proceeding
|
||||
|
||||
- **Ensure you have stopped all master and worker processes of Misskey.**
|
||||
- **Ensure you have backups of the database before performing any commands.**
|
||||
|
||||
## Misskey v13 and above
|
||||
|
||||
|
@ -77,15 +78,16 @@ NODE_ENV=production pnpm run migrate
|
|||
# build using prefered method
|
||||
```
|
||||
|
||||
## Foundkey
|
||||
## FoundKey
|
||||
|
||||
```sh
|
||||
cd packages/backend
|
||||
sed -i '12s/^/\/\//' ./migration/1663399074403-resize-comments-drive-file.js
|
||||
|
||||
LINE_NUM="$(npx typeorm migration:show -d ormconfig.js | grep -n uniformThemecolor1652859567549 | cut -d ':' -f 1)"
|
||||
NUM_MIGRATIONS="$(npx typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | nl)"
|
||||
NUM_MIGRATIONS="$(npx typeorm migration:show -d ormconfig.js | tail -n+"$LINE_NUM" | grep '\[X\]' | wc -l)"
|
||||
|
||||
for i in $(seq 1 $NUM_MIGRAIONS); do
|
||||
for i in $(seq 1 $NUM_MIGRATIONS); do
|
||||
npx typeorm migration:revert -d ormconfig.js
|
||||
done
|
||||
|
||||
|
@ -100,4 +102,4 @@ NODE_ENV=production pnpm run migrate
|
|||
|
||||
## Reverse
|
||||
|
||||
You ***cannot*** migrate back to Misskey from Calckey due to re-hashing passwords on signin with argon2. You can migrate from Calckey to Foundkey, though.
|
||||
You ***cannot*** migrate back to Misskey from Calckey due to re-hashing passwords on signin with argon2. You can migrate from Calckey to FoundKey, although this is not recommended due to FoundKey being end-of-life.
|
||||
|
|
|
@ -2144,3 +2144,6 @@ _skinTones:
|
|||
swipeOnMobile: Permet lliscar entre pàgines
|
||||
enableIdenticonGeneration: Habilitar la generació d'Identicon
|
||||
enableServerMachineStats: Habilitar les estadístiques del maquinari del servidor
|
||||
showPopup: Notificar els usuaris amb una finestra emergent
|
||||
showWithSparkles: Mostra amb espurnes
|
||||
youHaveUnreadAnnouncements: Tens anuncis sense llegir
|
||||
|
|
|
@ -645,6 +645,7 @@ useBlurEffectForModal: "Use blur effect for modals"
|
|||
useFullReactionPicker: "Use full-size reaction picker"
|
||||
width: "Width"
|
||||
height: "Height"
|
||||
xl: "XL"
|
||||
large: "Big"
|
||||
medium: "Medium"
|
||||
small: "Small"
|
||||
|
@ -1118,6 +1119,9 @@ enableIdenticonGeneration: "Enable Identicon generation"
|
|||
showPopup: "Notify users with popup"
|
||||
showWithSparkles: "Show with sparkles"
|
||||
youHaveUnreadAnnouncements: "You have unread announcements"
|
||||
donationLink: "Link to donation page"
|
||||
neverShow: "Don't show again"
|
||||
remindMeLater: "Maybe later"
|
||||
|
||||
_sensitiveMediaDetection:
|
||||
description: "Reduces the effort of server moderation through automatically recognizing
|
||||
|
@ -1216,6 +1220,10 @@ _aboutMisskey:
|
|||
source: "Source code"
|
||||
translation: "Translate Calckey"
|
||||
donate: "Donate to Calckey"
|
||||
donateTitle: "Enjoying Calckey?"
|
||||
pleaseDonateToCalckey: "Please consider donating to Calckey to support its development."
|
||||
pleaseDonateToHost: "Please also consider donating to your home server, {host}, to help support its operation costs."
|
||||
donateHost: "Donate to {host}"
|
||||
morePatrons: "We also appreciate the support of many other helpers not listed here.
|
||||
Thank you! 🥰"
|
||||
patrons: "Calckey patrons"
|
||||
|
|
|
@ -983,6 +983,8 @@ enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にす
|
|||
showPopup: "ポップアップを表示してユーザーに知らせる"
|
||||
showWithSparkles: "タイトルをキラキラさせる"
|
||||
youHaveUnreadAnnouncements: "未読のお知らせがあります"
|
||||
neverShow: "今後表示しない"
|
||||
remindMeLater: "また後で"
|
||||
|
||||
_sensitiveMediaDetection:
|
||||
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てられます。サーバーの負荷が少し増えます。"
|
||||
|
|
24
package.json
24
package.json
|
@ -1,16 +1,16 @@
|
|||
{
|
||||
"name": "calckey",
|
||||
"version": "14.0.0-rc3",
|
||||
"version": "14.0.0-dev71",
|
||||
"codename": "aqua",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://codeberg.org/calckey/calckey.git"
|
||||
},
|
||||
"packageManager": "pnpm@8.6.6",
|
||||
"packageManager": "pnpm@8.6.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r run build && pnpm run gulp",
|
||||
"build": "pnpm node ./scripts/build-greet.js && pnpm -r run build && pnpm run gulp",
|
||||
"rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp",
|
||||
"build": "pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp",
|
||||
"start": "pnpm --filter backend run start",
|
||||
"start:test": "pnpm --filter backend run start:test",
|
||||
"init": "pnpm run migrate",
|
||||
|
@ -21,13 +21,13 @@
|
|||
"watch": "pnpm run dev",
|
||||
"dev": "pnpm node ./scripts/dev.js",
|
||||
"dev:staging": "NODE_OPTIONS=--max_old_space_size=3072 NODE_ENV=development pnpm run build && pnpm run start",
|
||||
"lint": "pnpm -r run lint",
|
||||
"lint": "pnpm -r --parallel run lint",
|
||||
"cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts",
|
||||
"cy:run": "cypress run",
|
||||
"e2e": "start-server-and-test start:test http://localhost:61812 cy:run",
|
||||
"mocha": "pnpm --filter backend run mocha",
|
||||
"test": "pnpm run mocha",
|
||||
"format": "pnpm -r run format",
|
||||
"format": "pnpm -r --parallel run format",
|
||||
"clean": "pnpm node ./scripts/clean.js",
|
||||
"clean-all": "pnpm node ./scripts/clean-all.js",
|
||||
"cleanall": "pnpm run clean-all"
|
||||
|
@ -36,17 +36,17 @@
|
|||
"chokidar": "^3.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/api": "5.2.0",
|
||||
"@bull-board/ui": "5.2.0",
|
||||
"@bull-board/api": "5.6.0",
|
||||
"@bull-board/ui": "5.6.0",
|
||||
"@napi-rs/cli": "^2.16.1",
|
||||
"@tensorflow/tfjs": "^3.21.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.18",
|
||||
"@types/gulp": "4.0.10",
|
||||
"@types/gulp-rename": "2.0.1",
|
||||
"@types/gulp": "4.0.13",
|
||||
"@types/gulp-rename": "2.0.2",
|
||||
"@types/node": "20.4.1",
|
||||
"chalk": "4.1.2",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.11.0",
|
||||
|
@ -59,6 +59,6 @@
|
|||
"install-peers": "^1.0.4",
|
||||
"rome": "^12.1.3",
|
||||
"start-server-and-test": "1.15.2",
|
||||
"typescript": "4.9.4"
|
||||
"typescript": "5.1.6"
|
||||
}
|
||||
}
|
||||
|
|
15
packages/backend/migration/1689136347561-donation-link.js
Normal file
15
packages/backend/migration/1689136347561-donation-link.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
export class DonationLink1689136347561 {
|
||||
name = "DonationLink1689136347561";
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" ADD "donationLink" character varying(256)`,
|
||||
);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" DROP COLUMN "DonationLink1689136347561"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -25,16 +25,16 @@
|
|||
"@tensorflow/tfjs-node": "3.21.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/api": "5.2.0",
|
||||
"@bull-board/koa": "5.2.0",
|
||||
"@bull-board/ui": "5.2.0",
|
||||
"@bull-board/api": "5.6.0",
|
||||
"@bull-board/koa": "5.6.0",
|
||||
"@bull-board/ui": "5.6.0",
|
||||
"@discordapp/twemoji": "14.1.2",
|
||||
"@elastic/elasticsearch": "7.17.0",
|
||||
"@koa/cors": "3.4.3",
|
||||
"@koa/multer": "3.0.2",
|
||||
"@koa/router": "9.0.1",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@redocly/openapi-core": "1.0.0-beta.120",
|
||||
"@redocly/openapi-core": "1.0.0-beta.131",
|
||||
"@sinonjs/fake-timers": "9.1.2",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@tensorflow/tfjs": "^4.2.0",
|
||||
|
@ -45,17 +45,17 @@
|
|||
"autobind-decorator": "2.4.0",
|
||||
"autolinker": "4.0.0",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.1277.0",
|
||||
"aws-sdk": "2.1413.0",
|
||||
"axios": "^1.4.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "1.1.5",
|
||||
"blurhash": "2.0.5",
|
||||
"bull": "4.10.4",
|
||||
"cacheable-lookup": "7.0.0",
|
||||
"calckey-js": "workspace:*",
|
||||
"cbor": "8.1.0",
|
||||
"chalk": "5.2.0",
|
||||
"chalk": "5.3.0",
|
||||
"chalk-template": "0.4.0",
|
||||
"chokidar": "3.5.3",
|
||||
"chokidar": "^3.5.3",
|
||||
"cli-highlight": "2.1.11",
|
||||
"color-convert": "2.0.1",
|
||||
"content-disposition": "0.5.4",
|
||||
|
@ -68,15 +68,15 @@
|
|||
"got": "12.5.3",
|
||||
"hpagent": "0.1.2",
|
||||
"ioredis": "5.3.2",
|
||||
"ip-cidr": "3.0.11",
|
||||
"ip-cidr": "3.1.0",
|
||||
"is-svg": "4.3.2",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsdom": "20.0.3",
|
||||
"jsonld": "8.2.0",
|
||||
"jsrsasign": "10.6.1",
|
||||
"koa": "2.13.4",
|
||||
"jsrsasign": "10.8.6",
|
||||
"koa": "2.14.2",
|
||||
"koa-body": "^6.0.1",
|
||||
"koa-bodyparser": "4.3.0",
|
||||
"koa-bodyparser": "4.4.1",
|
||||
"koa-favicon": "2.1.0",
|
||||
"koa-json-body": "5.3.0",
|
||||
"koa-logger": "3.2.1",
|
||||
|
@ -98,9 +98,9 @@
|
|||
"nsfwjs": "2.4.2",
|
||||
"oauth": "^0.10.0",
|
||||
"os-utils": "0.0.14",
|
||||
"otpauth": "^9.1.2",
|
||||
"otpauth": "^9.1.3",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.11.0",
|
||||
"pg": "8.11.1",
|
||||
"private-ip": "2.3.4",
|
||||
"probe-image-size": "7.2.3",
|
||||
"promise-limit": "2.7.0",
|
||||
|
@ -110,7 +110,7 @@
|
|||
"qs": "6.11.2",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"re2": "1.19.0",
|
||||
"re2": "1.19.1",
|
||||
"redis-lock": "0.1.4",
|
||||
"redis-semaphore": "5.3.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
|
@ -119,7 +119,7 @@
|
|||
"rss-parser": "3.13.0",
|
||||
"sanitize-html": "2.10.0",
|
||||
"seedrandom": "^3.0.5",
|
||||
"semver": "7.5.1",
|
||||
"semver": "7.5.4",
|
||||
"sharp": "0.32.1",
|
||||
"sonic-channel": "^1.3.1",
|
||||
"stringz": "2.1.0",
|
||||
|
@ -130,27 +130,26 @@
|
|||
"tinycolor2": "1.5.2",
|
||||
"tmp": "0.2.1",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typeorm": "0.3.11",
|
||||
"typeorm": "0.3.17",
|
||||
"ulid": "2.3.0",
|
||||
"uuid": "9.0.0",
|
||||
"web-push": "3.6.1",
|
||||
"web-push": "3.6.3",
|
||||
"websocket": "1.0.34",
|
||||
"xev": "3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.1.62",
|
||||
"@swc/core": "^1.3.62",
|
||||
"@swc/core": "^1.3.68",
|
||||
"@types/adm-zip": "^0.5.0",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.15.9",
|
||||
"@types/cbor": "6.0.0",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/fluent-ffmpeg": "2.1.20",
|
||||
"@types/fluent-ffmpeg": "2.1.21",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/jsdom": "20.0.1",
|
||||
"@types/jsonld": "1.5.8",
|
||||
"@types/jsrsasign": "10.5.4",
|
||||
"@types/koa": "2.13.5",
|
||||
"@types/jsdom": "21.1.1",
|
||||
"@types/jsonld": "1.5.9",
|
||||
"@types/jsrsasign": "10.5.8",
|
||||
"@types/koa": "2.13.6",
|
||||
"@types/koa-bodyparser": "4.3.10",
|
||||
"@types/koa-cors": "0.0.2",
|
||||
"@types/koa-favicon": "2.0.21",
|
||||
|
@ -169,7 +168,7 @@
|
|||
"@types/probe-image-size": "^7.2.0",
|
||||
"@types/pug": "2.0.6",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/qrcode": "1.5.0",
|
||||
"@types/qrcode": "1.5.1",
|
||||
"@types/qs": "6.9.7",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "3.4.4",
|
||||
|
@ -177,17 +176,16 @@
|
|||
"@types/rename": "1.0.4",
|
||||
"@types/sanitize-html": "2.9.0",
|
||||
"@types/semver": "7.5.0",
|
||||
"@types/sharp": "0.31.1",
|
||||
"@types/sinonjs__fake-timers": "8.1.2",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/uuid": "8.3.4",
|
||||
"@types/uuid": "9.0.2",
|
||||
"@types/web-push": "3.3.2",
|
||||
"@types/websocket": "1.0.5",
|
||||
"@types/ws": "8.5.4",
|
||||
"@types/ws": "8.5.5",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint": "^8.44.0",
|
||||
"execa": "6.1.0",
|
||||
"json5": "2.2.3",
|
||||
"json5-loader": "4.0.1",
|
||||
|
@ -195,11 +193,11 @@
|
|||
"pug": "3.0.2",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"swc-loader": "^0.2.3",
|
||||
"ts-loader": "9.4.3",
|
||||
"ts-loader": "9.4.4",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.1.3",
|
||||
"webpack": "^5.85.1",
|
||||
"typescript": "5.1.6",
|
||||
"webpack": "^5.88.1",
|
||||
"ws": "8.13.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ export function nyaize(text: string): string {
|
|||
)
|
||||
.replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, "다냥")
|
||||
.replace(/(야(?=\?))|(야$)|(야(?= ))/gm, "냥")
|
||||
// zh-CN, zh-TW
|
||||
.replace(/(妙|庙|描|渺|瞄|秒|苗|藐|廟)/g, "喵")
|
||||
// el-GR
|
||||
.replaceAll("να", "νια")
|
||||
.replaceAll("ΝΑ", "ΝΙΑ")
|
||||
|
|
|
@ -556,4 +556,10 @@ export class Meta {
|
|||
default: true,
|
||||
})
|
||||
public enableIdenticonGeneration: boolean;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 256,
|
||||
nullable: true,
|
||||
})
|
||||
public donationLink: string | null;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type Bull from "bull";
|
||||
import type { DoneCallback } from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { Notes } from "@/models/index.js";
|
||||
|
@ -11,7 +12,7 @@ const logger = queueLogger.createSubLogger("index-all-notes");
|
|||
|
||||
export default async function indexAllNotes(
|
||||
job: Bull.Job<Record<string, unknown>>,
|
||||
done: () => void,
|
||||
done: DoneCallback,
|
||||
): Promise<void> {
|
||||
logger.info("Indexing all notes...");
|
||||
|
||||
|
@ -20,7 +21,7 @@ export default async function indexAllNotes(
|
|||
let total: number = (job.data.total as number) ?? 0;
|
||||
|
||||
let running = true;
|
||||
const take = 100000;
|
||||
const take = 10000;
|
||||
const batch = 100;
|
||||
while (running) {
|
||||
logger.info(
|
||||
|
@ -41,13 +42,14 @@ export default async function indexAllNotes(
|
|||
},
|
||||
relations: ["user"],
|
||||
});
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
logger.error(`Failed to query notes ${e}`);
|
||||
continue;
|
||||
done(e);
|
||||
break;
|
||||
}
|
||||
|
||||
if (notes.length === 0) {
|
||||
job.progress(100);
|
||||
await job.progress(100);
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ export default async function indexAllNotes(
|
|||
try {
|
||||
const count = await Notes.count();
|
||||
total = count;
|
||||
job.update({ indexedCount, cursor, total });
|
||||
await job.update({ indexedCount, cursor, total });
|
||||
} catch (e) {}
|
||||
|
||||
for (let i = 0; i < notes.length; i += batch) {
|
||||
|
@ -69,12 +71,12 @@ export default async function indexAllNotes(
|
|||
|
||||
indexedCount += chunk.length;
|
||||
const pct = (indexedCount / total) * 100;
|
||||
job.update({ indexedCount, cursor, total });
|
||||
job.progress(+pct.toFixed(1));
|
||||
await job.update({ indexedCount, cursor, total });
|
||||
await job.progress(+pct.toFixed(1));
|
||||
logger.info(`Indexed notes ${indexedCount}/${total ? total : "?"}`);
|
||||
}
|
||||
cursor = notes[notes.length - 1].id;
|
||||
job.update({ indexedCount, cursor, total });
|
||||
await job.update({ indexedCount, cursor, total });
|
||||
|
||||
if (notes.length < take) {
|
||||
running = false;
|
||||
|
|
|
@ -50,7 +50,7 @@ export async function importMastoPost(
|
|||
text: text || undefined,
|
||||
reply,
|
||||
renote: null,
|
||||
cw: post.sensitive,
|
||||
cw: post.object.sensitive ? post.object.summary : undefined,
|
||||
localOnly: false,
|
||||
visibility: "hidden",
|
||||
visibleUsers: [],
|
||||
|
|
|
@ -491,6 +491,11 @@ export const meta = {
|
|||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
donationLink: {
|
||||
type: "string",
|
||||
optional: true,
|
||||
nullable: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
@ -604,5 +609,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
experimentalFeatures: instance.experimentalFeatures,
|
||||
enableServerMachineStats: instance.enableServerMachineStats,
|
||||
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
||||
donationLink: instance.donationLink,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -177,6 +177,9 @@ export const paramDef = {
|
|||
postImports: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
enableServerMachineStats: { type: "boolean" },
|
||||
enableIdenticonGeneration: { type: "boolean" },
|
||||
donationLink: { type: "string", nullable: true },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
@ -568,6 +571,21 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.experimentalFeatures = ps.experimentalFeatures || undefined;
|
||||
}
|
||||
|
||||
if (ps.enableServerMachineStats !== undefined) {
|
||||
set.enableServerMachineStats = ps.enableServerMachineStats;
|
||||
}
|
||||
|
||||
if (ps.enableIdenticonGeneration !== undefined) {
|
||||
set.enableIdenticonGeneration = ps.enableIdenticonGeneration;
|
||||
}
|
||||
|
||||
if (ps.donationLink !== undefined) {
|
||||
set.donationLink = ps.donationLink;
|
||||
if (set.donationLink && !/^https?:\/\//i.test(set.donationLink)) {
|
||||
set.donationLink = `https://${set.donationLink}`;
|
||||
}
|
||||
}
|
||||
|
||||
await db.transaction(async (transactionalEntityManager) => {
|
||||
const metas = await transactionalEntityManager.find(Meta, {
|
||||
order: {
|
||||
|
|
|
@ -389,6 +389,11 @@ export const meta = {
|
|||
nullable: false,
|
||||
default: "⭐",
|
||||
},
|
||||
donationLink: {
|
||||
type: "string",
|
||||
optional: "true",
|
||||
nullable: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
@ -491,6 +496,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
translatorAvailable:
|
||||
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
|
||||
defaultReaction: instance.defaultReaction,
|
||||
donationLink: instance.donationLink,
|
||||
|
||||
...(ps.detail
|
||||
? {
|
||||
|
|
|
@ -247,7 +247,7 @@ export default class Connection {
|
|||
|
||||
for (const obj of objs) {
|
||||
const { type, body } = obj;
|
||||
console.log(type, body);
|
||||
// console.log(type, body);
|
||||
switch (type) {
|
||||
case "readNotification":
|
||||
this.onReadNotification(body);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"@syuilo/aiscript": "0.11.1",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/glob": "8.1.0",
|
||||
"@types/gulp": "4.0.11",
|
||||
"@types/gulp": "4.0.13",
|
||||
"@types/gulp-rename": "2.0.2",
|
||||
"@types/katex": "0.16.0",
|
||||
"@types/matter-js": "0.18.2",
|
||||
|
@ -29,8 +29,8 @@
|
|||
"@vue/compiler-sfc": "3.3.4",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autosize": "5.0.2",
|
||||
"blurhash": "1.1.5",
|
||||
"broadcast-channel": "4.19.1",
|
||||
"blurhash": "2.0.5",
|
||||
"broadcast-channel": "5.1.0",
|
||||
"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
|
||||
"calckey-js": "workspace:*",
|
||||
"chart.js": "4.3.0",
|
||||
|
@ -39,57 +39,58 @@
|
|||
"chartjs-plugin-gradient": "0.6.1",
|
||||
"chartjs-plugin-zoom": "2.0.1",
|
||||
"city-timezones": "^1.2.1",
|
||||
"compare-versions": "5.0.3",
|
||||
"compare-versions": "6.0.0",
|
||||
"cropperjs": "2.0.0-beta.2",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.11.0",
|
||||
"date-fns": "2.30.0",
|
||||
"emojilib": "github:thatonecalculator/emojilib",
|
||||
"escape-regexp": "0.0.1",
|
||||
"eventemitter3": "4.0.7",
|
||||
"focus-trap": "^7.4.3",
|
||||
"eventemitter3": "5.0.1",
|
||||
"fast-blurhash": "^1.1.2",
|
||||
"focus-trap": "^7.5.2",
|
||||
"focus-trap-vue": "^4.0.2",
|
||||
"gsap": "^3.11.5",
|
||||
"gsap": "^3.12.2",
|
||||
"idb-keyval": "6.2.1",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"json5": "2.2.3",
|
||||
"katex": "0.16.7",
|
||||
"katex": "0.16.8",
|
||||
"libopenmpt-wasm": "github:TheEssem/libopenmpt-packaging#build",
|
||||
"matter-js": "0.18.0",
|
||||
"mfm-js": "0.23.3",
|
||||
"photoswipe": "5.3.7",
|
||||
"photoswipe": "5.3.8",
|
||||
"prettier": "3.0.0",
|
||||
"prettier-plugin-vue": "1.1.6",
|
||||
"prismjs": "1.29.0",
|
||||
"punycode": "2.1.1",
|
||||
"punycode": "2.3.0",
|
||||
"querystring": "0.2.1",
|
||||
"rndstr": "1.0.0",
|
||||
"rollup": "3.23.1",
|
||||
"rollup": "3.26.2",
|
||||
"s-age": "1.1.2",
|
||||
"sass": "1.62.1",
|
||||
"sass": "1.63.6",
|
||||
"seedrandom": "3.0.5",
|
||||
"start-server-and-test": "1.15.2",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"swiper": "9.3.2",
|
||||
"swiper": "10.0.4",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.146.0",
|
||||
"throttle-debounce": "5.0.0",
|
||||
"tinycolor2": "1.5.2",
|
||||
"tsc-alias": "1.8.6",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tsc-alias": "1.8.7",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typescript": "5.1.3",
|
||||
"typescript": "5.1.6",
|
||||
"unicode-emoji-json": "^0.4.0",
|
||||
"uuid": "9.0.0",
|
||||
"vanilla-tilt": "1.8.0",
|
||||
"vite": "4.3.9",
|
||||
"vite": "4.4.2",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vue": "3.3.4",
|
||||
"vue-draggable-plus": "^0.2.2",
|
||||
"vue-isyourpasswordsafe": "^2.0.0",
|
||||
"vue-plyr": "^7.0.0",
|
||||
"vue-prism-editor": "2.0.0-alpha.2",
|
||||
"vuedraggable": "4.1.0"
|
||||
"vue-prism-editor": "2.0.0-alpha.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,13 @@
|
|||
<MkSparkle v-if="isGoodNews">{{ title }}</MkSparkle>
|
||||
<p v-else>{{ title }}</p>
|
||||
</div>
|
||||
<div :class="$style.time">
|
||||
<MkTime :time="announcement.createdAt" />
|
||||
<div v-if="announcement.updatedAt">
|
||||
{{ i18n.ts.updatedAt }}:
|
||||
<MkTime :time="announcement.createdAt" />
|
||||
</div>
|
||||
</div>
|
||||
<Mfm :text="text" />
|
||||
<img
|
||||
v-if="imageUrl != null"
|
||||
|
@ -68,6 +75,10 @@ const gotIt = () => {
|
|||
}
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.gotIt {
|
||||
margin: 8px 0 0 0;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
<template #default="{ width, height }">
|
||||
<div
|
||||
class="mk-cropper-dialog"
|
||||
:style="`--vw: ${width}px; --vh: ${height}px;`"
|
||||
:style="`--vw: ${width ? `${width}px` : '100%'}; --vh: ${
|
||||
height ? `${height}px` : '100%'
|
||||
};`"
|
||||
>
|
||||
<Transition name="fade">
|
||||
<div v-if="loading" class="loading">
|
||||
|
|
180
packages/client/src/components/MkDonation.vue
Normal file
180
packages/client/src/components/MkDonation.vue
Normal file
|
@ -0,0 +1,180 @@
|
|||
<template>
|
||||
<transition name="slide-fade">
|
||||
<div v-if="show" class="_panel _shadow _acrylic" :class="$style.root">
|
||||
<div :class="$style.icon">
|
||||
<i class="ph-hand-heart ph-bold ph-5x" />
|
||||
</div>
|
||||
<div :class="$style.main">
|
||||
<div :class="$style.title">
|
||||
{{ i18n.ts._aboutMisskey.donateTitle }}
|
||||
</div>
|
||||
<div :class="$style.text">
|
||||
{{ i18n.ts._aboutMisskey.pleaseDonateToCalckey }}
|
||||
<p v-if="$instance.donationLink">
|
||||
{{
|
||||
i18n.t("_aboutMisskey.pleaseDonateToHost", {
|
||||
host: hostname,
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="_flexList" style="gap: 0.6rem;">
|
||||
<MkButton
|
||||
primary
|
||||
@click="
|
||||
openExternal('https://opencollective.com/calckey')
|
||||
"
|
||||
>{{ i18n.ts._aboutMisskey.donate }}</MkButton
|
||||
>
|
||||
<MkButton
|
||||
v-if="$instance.donationLink"
|
||||
gradate
|
||||
@click="openExternal($instance.donationLink)"
|
||||
>{{
|
||||
i18n.t("_aboutMisskey.donateHost", {
|
||||
host: hostname,
|
||||
})
|
||||
}}</MkButton
|
||||
>
|
||||
</div>
|
||||
<div class="_flexList" style="margin-top: 0.6rem">
|
||||
<MkButton @click="close">{{
|
||||
i18n.ts.remindMeLater
|
||||
}}</MkButton>
|
||||
<MkButton @click="neverShow">{{
|
||||
i18n.ts.neverShow
|
||||
}}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
<button class="_button" :class="$style.close" @click="close">
|
||||
<i class="ph-x ph-bold ph-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick } from "vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import { host } from "@/config";
|
||||
import { i18n } from "@/i18n";
|
||||
import * as os from "@/os";
|
||||
import { instance } from "@/instance";
|
||||
|
||||
let show = ref(false);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: "closed"): void;
|
||||
}>();
|
||||
|
||||
const hostname = instance.name?.length < 38 ? instance.name : host;
|
||||
|
||||
const zIndex = os.claimZIndex("low");
|
||||
|
||||
function slideIn() {
|
||||
show.value = false;
|
||||
nextTick(() => {
|
||||
show.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
slideIn();
|
||||
|
||||
function close() {
|
||||
localStorage.setItem("latestDonationInfoShownAt", Date.now().toString());
|
||||
emit("closed");
|
||||
show.value = false;
|
||||
}
|
||||
|
||||
function neverShow() {
|
||||
localStorage.setItem("neverShowDonationInfo", "true");
|
||||
close();
|
||||
}
|
||||
|
||||
function openExternal(link) {
|
||||
window.open(link, "_blank");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.slide-fade-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.slide-fade-enter-active {
|
||||
transition: opacity 0.5s, transform 0.5s ease-out;
|
||||
}
|
||||
|
||||
.slide-fade-enter-to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.slide-fade-leave-from {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
transition: opacity 0.5s, transform 0.5s ease-out;
|
||||
}
|
||||
|
||||
.slide-fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
position: fixed;
|
||||
z-index: v-bind(zIndex);
|
||||
bottom: var(--margin);
|
||||
left: 2%;
|
||||
bottom: 2%;
|
||||
margin: auto;
|
||||
box-sizing: border-box;
|
||||
width: calc(100% - (var(--margin) * 2));
|
||||
max-width: 500px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
text-align: center;
|
||||
padding-top: 25px;
|
||||
width: 100px;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.icon {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 450px) {
|
||||
.icon {
|
||||
width: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 25px 25px 25px 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
.text {
|
||||
margin: 0.7em 0 1em 0;
|
||||
}
|
||||
</style>
|
|
@ -12,7 +12,7 @@
|
|||
:transparent-bg="true"
|
||||
:manual-showing="manualShowing"
|
||||
:src="src"
|
||||
@click="modal?.close()"
|
||||
@click="checkForShift"
|
||||
@opening="opening"
|
||||
@close="emit('close')"
|
||||
@closed="emit('closed')"
|
||||
|
@ -31,7 +31,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
||||
import MkModal from "@/components/MkModal.vue";
|
||||
import MkEmojiPicker from "@/components/MkEmojiPicker.vue";
|
||||
import { defaultStore } from "@/store";
|
||||
|
@ -58,20 +58,49 @@ const emit = defineEmits<{
|
|||
|
||||
const modal = ref<InstanceType<typeof MkModal>>();
|
||||
const picker = ref<InstanceType<typeof MkEmojiPicker>>();
|
||||
const isShiftKeyPressed = ref(false);
|
||||
|
||||
const keydownHandler = (e) => {
|
||||
if (e.key === "Shift") {
|
||||
isShiftKeyPressed.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const keyupHandler = (e) => {
|
||||
if (e.key === "Shift") {
|
||||
isShiftKeyPressed.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
function checkForShift(ev?: MouseEvent) {
|
||||
if (!isShiftKeyPressed.value) {
|
||||
modal.value?.close(ev);
|
||||
}
|
||||
}
|
||||
|
||||
function chosen(emoji: any) {
|
||||
emit("done", emoji);
|
||||
modal.value?.close();
|
||||
checkForShift();
|
||||
}
|
||||
|
||||
function opening() {
|
||||
try {
|
||||
picker.value?.reset();
|
||||
} catch (e) {
|
||||
console.error(`Something's wrong with restting the emoji picker: ${e}`);
|
||||
console.error("Something's wrong with resetting the emoji picker", e);
|
||||
}
|
||||
picker.value?.focus();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("keydown", keydownHandler);
|
||||
window.addEventListener("keyup", keyupHandler);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("keydown", keydownHandler);
|
||||
window.removeEventListener("keyup", keyupHandler);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from "vue";
|
||||
import { decode } from "blurhash";
|
||||
import { decodeBlurHash } from "fast-blurhash";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -47,8 +47,8 @@ const canvas = $ref<HTMLCanvasElement>();
|
|||
let loaded = $ref(false);
|
||||
|
||||
function draw() {
|
||||
if (props.hash == null) return;
|
||||
const pixels = decode(props.hash, props.size, props.size);
|
||||
if (props.hash == null || canvas == null) return;
|
||||
const pixels = decodeBlurHash(props.hash, props.size, props.size);
|
||||
const ctx = canvas.getContext("2d");
|
||||
const imageData = ctx!.createImageData(props.size, props.size);
|
||||
imageData.data.set(pixels);
|
||||
|
|
|
@ -226,11 +226,13 @@ watch(
|
|||
display: flex;
|
||||
min-width: max-content;
|
||||
width: 110px;
|
||||
transition: width 0.2s cubic-bezier(0,0,0,1);
|
||||
transition: width 0.2s cubic-bezier(0, 0, 0, 1);
|
||||
[data-plyr="volume"] {
|
||||
width: 0;
|
||||
flex-grow: 1;
|
||||
transition: margin 0.3s, opacity .2s 0.2s;
|
||||
transition:
|
||||
margin 0.3s,
|
||||
opacity 0.2s 0.2s;
|
||||
}
|
||||
&:not(:hover):not(:focus-within) {
|
||||
width: 0px;
|
||||
|
@ -238,7 +240,9 @@ watch(
|
|||
[data-plyr="volume"] {
|
||||
margin-inline: 0px;
|
||||
opacity: 0;
|
||||
transition: margin 0.3s, opacity 0.1s;
|
||||
transition:
|
||||
margin 0.3s,
|
||||
opacity 0.1s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -869,6 +869,9 @@ defineExpose({
|
|||
margin: 0;
|
||||
padding: 8px;
|
||||
opacity: 0.7;
|
||||
&:disabled {
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
flex-grow: 1;
|
||||
max-width: 3.5em;
|
||||
width: max-content;
|
||||
|
|
|
@ -477,6 +477,9 @@ function noteClick(e) {
|
|||
margin: 0;
|
||||
padding: 8px;
|
||||
opacity: 0.7;
|
||||
&:disabled {
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
flex-grow: 1;
|
||||
max-width: 3.5em;
|
||||
width: max-content;
|
||||
|
|
|
@ -1,186 +1,162 @@
|
|||
<template>
|
||||
<div v-show="files.length != 0" class="skeikyzd">
|
||||
<XDraggable
|
||||
<VueDraggable
|
||||
v-model="_files"
|
||||
class="files"
|
||||
item-key="id"
|
||||
animation="150"
|
||||
delay="100"
|
||||
delay-on-touch-only="true"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div
|
||||
class="file"
|
||||
@click="showFileMenu(element, $event)"
|
||||
@contextmenu.prevent="showFileMenu(element, $event)"
|
||||
>
|
||||
<MkDriveFileThumbnail
|
||||
:data-id="element.id"
|
||||
class="thumbnail"
|
||||
:file="element"
|
||||
fit="cover"
|
||||
/>
|
||||
<div v-if="element.isSensitive" class="sensitive">
|
||||
<i class="ph-warning ph-bold ph-lg icon"></i>
|
||||
</div>
|
||||
<div
|
||||
class="file"
|
||||
v-for="element in _files"
|
||||
:key="element.id"
|
||||
@click="showFileMenu(element, $event)"
|
||||
@contextmenu.prevent="showFileMenu(element, $event)"
|
||||
>
|
||||
<MkDriveFileThumbnail
|
||||
:data-id="element.id"
|
||||
class="thumbnail"
|
||||
:file="element"
|
||||
fit="cover"
|
||||
/>
|
||||
<div v-if="element.isSensitive" class="sensitive">
|
||||
<i class="ph-warning ph-bold ph-lg icon"></i>
|
||||
</div>
|
||||
</template>
|
||||
</XDraggable>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
<p class="remain">{{ 16 - files.length }}/16</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, ref, computed } from "vue";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XDraggable: defineAsyncComponent(() =>
|
||||
import("vuedraggable").then((x) => x.default),
|
||||
),
|
||||
MkDriveFileThumbnail,
|
||||
const props = defineProps({
|
||||
files: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
|
||||
props: {
|
||||
files: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
detachMediaFn: {
|
||||
type: Function,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ["updated", "detach", "changeSensitive", "changeName"],
|
||||
|
||||
data() {
|
||||
return {
|
||||
menu: null as Promise<null> | null,
|
||||
i18n,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
_files: {
|
||||
get() {
|
||||
return this.files;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("updated", value);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
detachMedia(id) {
|
||||
if (this.detachMediaFn) {
|
||||
this.detachMediaFn(id);
|
||||
} else {
|
||||
this.$emit("detach", id);
|
||||
}
|
||||
},
|
||||
toggleSensitive(file) {
|
||||
os.api("drive/files/update", {
|
||||
fileId: file.id,
|
||||
isSensitive: !file.isSensitive,
|
||||
}).then(() => {
|
||||
this.$emit("changeSensitive", file, !file.isSensitive);
|
||||
});
|
||||
},
|
||||
async rename(file) {
|
||||
const { canceled, result } = await os.inputText({
|
||||
title: i18n.ts.enterFileName,
|
||||
default: file.name,
|
||||
allowEmpty: false,
|
||||
});
|
||||
if (canceled) return;
|
||||
os.api("drive/files/update", {
|
||||
fileId: file.id,
|
||||
name: result,
|
||||
}).then(() => {
|
||||
this.$emit("changeName", file, result);
|
||||
file.name = result;
|
||||
});
|
||||
},
|
||||
|
||||
async describe(file) {
|
||||
os.popup(
|
||||
defineAsyncComponent(
|
||||
() => import("@/components/MkMediaCaption.vue"),
|
||||
),
|
||||
{
|
||||
title: i18n.ts.describeFile,
|
||||
input: {
|
||||
placeholder: i18n.ts.inputNewDescription,
|
||||
default: file.comment !== null ? file.comment : "",
|
||||
},
|
||||
image: file,
|
||||
},
|
||||
{
|
||||
done: (result) => {
|
||||
if (!result || result.canceled) return;
|
||||
let comment =
|
||||
result.result.length === 0 ? null : result.result;
|
||||
os.api("drive/files/update", {
|
||||
fileId: file.id,
|
||||
comment: comment,
|
||||
}).then(() => {
|
||||
file.comment = comment;
|
||||
});
|
||||
},
|
||||
},
|
||||
"closed",
|
||||
);
|
||||
},
|
||||
|
||||
showFileMenu(file, ev: MouseEvent) {
|
||||
if (this.menu) return;
|
||||
this.menu = os
|
||||
.popupMenu(
|
||||
[
|
||||
{
|
||||
text: i18n.ts.renameFile,
|
||||
icon: "ph-cursor-text ph-bold ph-lg",
|
||||
action: () => {
|
||||
this.rename(file);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: file.isSensitive
|
||||
? i18n.ts.unmarkAsSensitive
|
||||
: i18n.ts.markAsSensitive,
|
||||
icon: file.isSensitive
|
||||
? "ph-eye ph-bold ph-lg"
|
||||
: "ph-eye-slash ph-bold ph-lg",
|
||||
action: () => {
|
||||
this.toggleSensitive(file);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.describeFile,
|
||||
icon: "ph-subtitles ph-bold ph-lg",
|
||||
action: () => {
|
||||
this.describe(file);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.attachCancel,
|
||||
icon: "ph-x ph-bold ph-lg",
|
||||
action: () => {
|
||||
this.detachMedia(file.id);
|
||||
},
|
||||
},
|
||||
],
|
||||
ev.currentTarget ?? ev.target,
|
||||
)
|
||||
.then(() => (this.menu = null));
|
||||
},
|
||||
detachMediaFn: {
|
||||
type: Function,
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits([
|
||||
"updated",
|
||||
"detach",
|
||||
"changeSensitive",
|
||||
"changeName",
|
||||
]);
|
||||
|
||||
const _files = computed({
|
||||
get: () => props.files,
|
||||
set: (value) => emits("updated", value),
|
||||
});
|
||||
|
||||
const detachMedia = (id) => {
|
||||
if (props.detachMediaFn) {
|
||||
props.detachMediaFn(id);
|
||||
} else {
|
||||
emits("detach", id);
|
||||
}
|
||||
};
|
||||
|
||||
function toggleSensitive(file) {
|
||||
os.api("drive/files/update", {
|
||||
fileId: file.id,
|
||||
isSensitive: !file.isSensitive,
|
||||
}).then(() => {
|
||||
emits("changeSensitive", file, !file.isSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
async function rename(file) {
|
||||
const { canceled, result } = await os.inputText({
|
||||
title: i18n.ts.enterFileName,
|
||||
default: file.name,
|
||||
});
|
||||
if (canceled) return;
|
||||
os.api("drive/files/update", {
|
||||
fileId: file.id,
|
||||
name: result,
|
||||
}).then(() => {
|
||||
emits("changeName", file, result);
|
||||
file.name = result;
|
||||
});
|
||||
}
|
||||
|
||||
async function describe(file) {
|
||||
os.popup(
|
||||
defineAsyncComponent(() => import("@/components/MkMediaCaption.vue")),
|
||||
{
|
||||
title: i18n.ts.describeFile,
|
||||
input: {
|
||||
placeholder: i18n.ts.inputNewDescription,
|
||||
default: file.comment !== null ? file.comment : "",
|
||||
},
|
||||
image: file,
|
||||
},
|
||||
{
|
||||
done: (result) => {
|
||||
if (!result || result.canceled) return;
|
||||
let comment = result.result.length === 0 ? null : result.result;
|
||||
os.api("drive/files/update", {
|
||||
fileId: file.id,
|
||||
comment: comment,
|
||||
}).then(() => {
|
||||
file.comment = comment;
|
||||
});
|
||||
},
|
||||
},
|
||||
"closed",
|
||||
);
|
||||
}
|
||||
|
||||
function showFileMenu(file, ev: MouseEvent) {
|
||||
os.popupMenu(
|
||||
[
|
||||
{
|
||||
text: i18n.ts.renameFile,
|
||||
icon: "ph-cursor-text ph-bold ph-lg",
|
||||
action: () => {
|
||||
rename(file);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: file.isSensitive
|
||||
? i18n.ts.unmarkAsSensitive
|
||||
: i18n.ts.markAsSensitive,
|
||||
icon: file.isSensitive
|
||||
? "ph-eye ph-bold ph-lg"
|
||||
: "ph-eye-slash ph-bold ph-lg",
|
||||
action: () => {
|
||||
toggleSensitive(file);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.describeFile,
|
||||
icon: "ph-subtitles ph-bold ph-lg",
|
||||
action: () => {
|
||||
describe(file);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: i18n.ts.attachCancel,
|
||||
icon: "ph-x ph-bold ph-lg",
|
||||
action: () => {
|
||||
detachMedia(file.id);
|
||||
},
|
||||
},
|
||||
],
|
||||
(ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -219,8 +195,8 @@ export default defineComponent({
|
|||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
background: rgba(17, 17, 17, 0.7);
|
||||
color: #fff;
|
||||
background: var(--header);
|
||||
color: var(--fg);
|
||||
|
||||
> .icon {
|
||||
margin: auto;
|
||||
|
|
|
@ -10,8 +10,13 @@
|
|||
<i class="ph-repeat ph-bold ph-lg"></i>
|
||||
<p v-if="count > 0 && !detailedView" class="count">{{ count }}</p>
|
||||
</button>
|
||||
<button v-else class="eddddedb _button">
|
||||
<i class="ph-prohibit ph-bold ph-lg"></i>
|
||||
<button
|
||||
v-else
|
||||
class="eddddedb _button"
|
||||
disabled="true"
|
||||
v-tooltip.noDelay.bottom="i18n.ts.disabled"
|
||||
>
|
||||
<i class="ph-repeat ph-bold ph-lg"></i>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -253,6 +253,9 @@ onUnmounted(() => {
|
|||
font-size: 1em;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 0.2em;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: transparent;
|
||||
transition: text-decoration-color 0.2s;
|
||||
}
|
||||
p {
|
||||
margin-bottom: -0.5em;
|
||||
|
@ -279,7 +282,7 @@ onUnmounted(() => {
|
|||
&:focus-within {
|
||||
background: var(--panelHighlight);
|
||||
h3 {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,13 +28,8 @@
|
|||
i18n.ts.close
|
||||
}}</MkButton>
|
||||
</header>
|
||||
<XDraggable
|
||||
v-model="widgets_"
|
||||
item-key="id"
|
||||
handle=".handle"
|
||||
animation="150"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<VueDraggable v-model="widgets_" handle=".handle" animation="150">
|
||||
<div v-for="element in widgets_" :key="element.id">
|
||||
<div class="customize-container">
|
||||
<button
|
||||
class="config _button"
|
||||
|
@ -58,8 +53,8 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</XDraggable>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
</template>
|
||||
<component
|
||||
:is="`mkw-${widget.name}`"
|
||||
|
@ -78,14 +73,13 @@
|
|||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, reactive, ref, computed } from "vue";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import MkSelect from "@/components/form/select.vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import { widgets as widgetDefs } from "@/widgets";
|
||||
import * as os from "@/os";
|
||||
import { i18n } from "@/i18n";
|
||||
|
||||
const XDraggable = defineAsyncComponent(() => import("vuedraggable"));
|
||||
|
||||
type Widget = {
|
||||
name: string;
|
||||
id: string;
|
||||
|
|
|
@ -69,7 +69,7 @@ const alt = computed(() =>
|
|||
vertical-align: -0.25em;
|
||||
|
||||
&.custom {
|
||||
height: 2.5em;
|
||||
height: 2em;
|
||||
vertical-align: middle;
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
|
|
|
@ -75,13 +75,12 @@ const target = self ? null : "_blank";
|
|||
|
||||
<style lang="scss" scoped>
|
||||
.url {
|
||||
white-space: nowrap;
|
||||
max-width: 80%;
|
||||
display: inline-block;
|
||||
overflow: clip;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none !important;
|
||||
line-height: 1.05;
|
||||
> span {
|
||||
text-decoration: underline var(--fgTransparent);
|
||||
text-decoration-thickness: 1px;
|
||||
transition: text-decoration-color 0.2s;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
padding-left: 2px;
|
||||
|
@ -111,5 +110,9 @@ const target = self ? null : "_blank";
|
|||
> .hash {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&:hover span {
|
||||
text-decoration-color: var(--link);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -409,7 +409,6 @@ export default defineComponent({
|
|||
key: Math.random(),
|
||||
to: `/tags/${encodeURIComponent(token.props.hashtag)}`,
|
||||
style: "color:var(--hashtag);",
|
||||
class: "_link",
|
||||
},
|
||||
`#${token.props.hashtag}`,
|
||||
),
|
||||
|
|
|
@ -450,6 +450,29 @@ function checkForSplash() {
|
|||
}
|
||||
localStorage.setItem("lastUsed", Date.now().toString());
|
||||
|
||||
const latestDonationInfoShownAt = localStorage.getItem(
|
||||
"latestDonationInfoShownAt",
|
||||
);
|
||||
const neverShowDonationInfo = localStorage.getItem("neverShowDonationInfo");
|
||||
if (
|
||||
neverShowDonationInfo !== "true" &&
|
||||
new Date($i.createdAt).getTime() < Date.now() - 1000 * 60 * 60 * 24 * 3 &&
|
||||
!location.pathname.startsWith("/miauth")
|
||||
) {
|
||||
if (
|
||||
latestDonationInfoShownAt == null ||
|
||||
new Date(latestDonationInfoShownAt).getTime() <
|
||||
Date.now() - 1000 * 60 * 60 * 24 * 30
|
||||
) {
|
||||
popup(
|
||||
defineAsyncComponent(() => import("@/components/MkDonation.vue")),
|
||||
{},
|
||||
{},
|
||||
"closed",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ("Notification" in window) {
|
||||
// 許可を得ていなかったらリクエスト
|
||||
if (Notification.permission === "default") {
|
||||
|
|
|
@ -101,8 +101,9 @@
|
|||
><Mfm
|
||||
:text="'@freeplay@calckey.social (UI/UX)'"
|
||||
/></FormLink>
|
||||
<FormLink to="/@nmkj@calckey.jp"
|
||||
><Mfm :text="'@nmkj@calckey.jp (Backend)'"
|
||||
<FormLink to="/@namekuji@calckey.social"
|
||||
><Mfm
|
||||
:text="'@namekuji@calckey.social (Backend)'"
|
||||
/></FormLink>
|
||||
<FormLink to="/@dev@post.naskya.net"
|
||||
><Mfm :text="'@dev@post.naskya.net (Backend)'"
|
||||
|
|
|
@ -93,6 +93,21 @@
|
|||
external
|
||||
>{{ i18n.ts.tos }}</FormLink
|
||||
>
|
||||
<FormLink
|
||||
v-if="$instance.donationLink"
|
||||
:to="$instance.donationLink"
|
||||
external
|
||||
>
|
||||
<template #icon
|
||||
><i class="ph-money ph-bold ph-lg"></i
|
||||
></template>
|
||||
{{
|
||||
i18n.t("_aboutMisskey.donateHost", {
|
||||
host: $instance.name || host,
|
||||
})
|
||||
}}
|
||||
<template #suffix>Donate</template>
|
||||
</FormLink>
|
||||
</FormSection>
|
||||
|
||||
<FormSuspense :p="initStats">
|
||||
|
@ -163,7 +178,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import XEmojis from "./about.emojis.vue";
|
||||
import XFederation from "./about.federation.vue";
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import MkSwitch from "@/components/form/switch.vue";
|
||||
|
|
|
@ -53,6 +53,20 @@
|
|||
i18n.ts.maintainerEmail
|
||||
}}</template>
|
||||
</FormInput>
|
||||
|
||||
<FormInput
|
||||
v-model="donationLink"
|
||||
class="_formBlock"
|
||||
>
|
||||
<template #prefix
|
||||
><i
|
||||
class="ph-hand-heart ph-bold ph-lg"
|
||||
></i
|
||||
></template>
|
||||
<template #label>{{
|
||||
i18n.ts.donationLink
|
||||
}}</template>
|
||||
</FormInput>
|
||||
</FormSplit>
|
||||
|
||||
<FormTextarea v-model="pinnedUsers" class="_formBlock">
|
||||
|
@ -435,6 +449,7 @@ let description: string | null = $ref(null);
|
|||
let tosUrl: string | null = $ref(null);
|
||||
let maintainerName: string | null = $ref(null);
|
||||
let maintainerEmail: string | null = $ref(null);
|
||||
let donationLink: string | null = $ref(null);
|
||||
let iconUrl: string | null = $ref(null);
|
||||
let bannerUrl: string | null = $ref(null);
|
||||
let logoImageUrl: string | null = $ref(null);
|
||||
|
@ -481,6 +496,7 @@ async function init() {
|
|||
defaultDarkTheme = meta.defaultDarkTheme;
|
||||
maintainerName = meta.maintainerName;
|
||||
maintainerEmail = meta.maintainerEmail;
|
||||
donationLink = meta.donationLink;
|
||||
enableLocalTimeline = !meta.disableLocalTimeline;
|
||||
enableGlobalTimeline = !meta.disableGlobalTimeline;
|
||||
enableRecommendedTimeline = !meta.disableRecommendedTimeline;
|
||||
|
@ -527,6 +543,7 @@ function save() {
|
|||
defaultDarkTheme: defaultDarkTheme === "" ? null : defaultDarkTheme,
|
||||
maintainerName,
|
||||
maintainerEmail,
|
||||
donationLink,
|
||||
disableLocalTimeline: !enableLocalTimeline,
|
||||
disableGlobalTimeline: !enableGlobalTimeline,
|
||||
disableRecommendedTimeline: !enableRecommendedTimeline,
|
||||
|
|
|
@ -15,8 +15,13 @@
|
|||
class="_card announcement"
|
||||
>
|
||||
<div class="_title">
|
||||
<span v-if="$i && !announcement.isRead">🆕 </span
|
||||
>{{ announcement.title }}
|
||||
<span v-if="$i && !announcement.isRead">🆕 </span>
|
||||
<h3>{{ announcement.title }}</h3>
|
||||
<MkTime :time="announcement.createdAt" />
|
||||
<div v-if="announcement.updatedAt">
|
||||
{{ i18n.ts.updatedAt }}:
|
||||
<MkTime :time="announcement.createdAt" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="_content">
|
||||
<Mfm :text="announcement.text" />
|
||||
|
@ -76,6 +81,10 @@ definePageMetadata({
|
|||
margin-bottom: var(--margin);
|
||||
}
|
||||
|
||||
> ._title {
|
||||
padding: 14px 32px !important;
|
||||
}
|
||||
|
||||
> ._content {
|
||||
> img {
|
||||
display: block;
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, defineComponent, inject, watch } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import MkChannelPreview from "@/components/MkChannelPreview.vue";
|
||||
import MkChannelList from "@/components/MkChannelList.vue";
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, onMounted } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import XFeatured from "./explore.featured.vue";
|
||||
import XUsers from "./explore.users.vue";
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineComponent, watch, onMounted } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import MkFolder from "@/components/MkFolder.vue";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
|
|
|
@ -338,7 +338,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import type * as calckey from "calckey-js";
|
||||
import MkChart from "@/components/MkChart.vue";
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, markRaw, onMounted, onUnmounted, watch } from "vue";
|
||||
import * as Acct from "calckey-js/built/acct";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import MkButton from "@/components/MkButton.vue";
|
||||
import MkChatPreview from "@/components/MkChatPreview.vue";
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import { notificationTypes } from "calckey-js";
|
||||
import XNotifications from "@/components/MkNotifications.vue";
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
<template>
|
||||
<XDraggable
|
||||
<VueDraggable
|
||||
v-model="blocks"
|
||||
tag="div"
|
||||
item-key="id"
|
||||
handle=".drag-handle"
|
||||
:group="{ name: 'blocks' }"
|
||||
animation="150"
|
||||
swap-threshold="0.5"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<component
|
||||
:is="'x-' + element.type"
|
||||
:value="element"
|
||||
:hpml="hpml"
|
||||
@update:value="updateItem"
|
||||
@remove="() => removeItem(element)"
|
||||
/>
|
||||
</template>
|
||||
</XDraggable>
|
||||
<component
|
||||
v-for="element in blocks"
|
||||
:key="element"
|
||||
:is="'x-' + element.type"
|
||||
:value="element"
|
||||
:hpml="hpml"
|
||||
@update:value="updateItem"
|
||||
@remove="() => removeItem(element)"
|
||||
/>
|
||||
</VueDraggable>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import XSection from "./els/page-editor.el.section.vue";
|
||||
import XText from "./els/page-editor.el.text.vue";
|
||||
import XTextarea from "./els/page-editor.el.textarea.vue";
|
||||
|
@ -41,9 +41,7 @@ import * as os from "@/os";
|
|||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XDraggable: defineAsyncComponent(() =>
|
||||
import("vuedraggable").then((x) => x.default),
|
||||
),
|
||||
VueDraggable,
|
||||
XSection,
|
||||
XText,
|
||||
XImage,
|
||||
|
|
|
@ -118,29 +118,28 @@
|
|||
|
||||
<div v-else-if="tab === 'variables'">
|
||||
<div class="qmuvgica">
|
||||
<XDraggable
|
||||
<VueDraggable
|
||||
v-show="variables.length > 0"
|
||||
v-model="variables"
|
||||
tag="div"
|
||||
class="variables"
|
||||
item-key="name"
|
||||
handle=".drag-handle"
|
||||
:group="{ name: 'variables' }"
|
||||
animation="150"
|
||||
swap-threshold="0.5"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<XVariable
|
||||
:model-value="element"
|
||||
:removable="true"
|
||||
:hpml="hpml"
|
||||
:name="element.name"
|
||||
:title="element.name"
|
||||
:draggable="true"
|
||||
@remove="() => removeVariable(element)"
|
||||
/>
|
||||
</template>
|
||||
</XDraggable>
|
||||
<XVariable
|
||||
v-for="element in variables"
|
||||
:key="element.name"
|
||||
:model-value="element"
|
||||
:removable="true"
|
||||
:hpml="hpml"
|
||||
:name="element.name"
|
||||
:title="element.name"
|
||||
:draggable="true"
|
||||
@remove="() => removeVariable(element)"
|
||||
/>
|
||||
</VueDraggable>
|
||||
|
||||
<MkButton
|
||||
v-if="!readonly"
|
||||
|
@ -174,6 +173,7 @@ import { blockDefs } from "@/scripts/hpml/index";
|
|||
import { HpmlTypeChecker } from "@/scripts/hpml/type-checker";
|
||||
import { url } from "@/config";
|
||||
import { collectPageVars } from "@/scripts/collect-page-vars";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import * as os from "@/os";
|
||||
import { selectFile } from "@/scripts/select-file";
|
||||
import { mainRouter } from "@/router";
|
||||
|
@ -181,10 +181,6 @@ import { i18n } from "@/i18n";
|
|||
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||
import { $i } from "@/account";
|
||||
|
||||
const XDraggable = defineAsyncComponent(() =>
|
||||
import("vuedraggable").then((x) => x.default),
|
||||
);
|
||||
|
||||
const props = defineProps<{
|
||||
initPageId?: string;
|
||||
initPageName?: string;
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, onMounted } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import MkPagePreview from "@/components/MkPagePreview.vue";
|
||||
import MkPagination from "@/components/MkPagination.vue";
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, onMounted } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import XNotes from "@/components/MkNotes.vue";
|
||||
import XUserList from "@/components/MkUserList.vue";
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
<p>
|
||||
{{ `${i18n.ts.lastUsedDate}: ${key.lastUsed}` }}
|
||||
</p>
|
||||
<div class="_buttons _flexList">
|
||||
<div class="_flexList">
|
||||
<MkButton @click="renameKey(key)"
|
||||
><i
|
||||
class="ph-pencil-line ph-bold ph-lg"
|
||||
|
|
|
@ -10,32 +10,30 @@
|
|||
i18n.ts.reactionSettingDescription
|
||||
}}</template>
|
||||
<div v-panel style="border-radius: 6px">
|
||||
<XDraggable
|
||||
<VueDraggable
|
||||
v-model="reactions"
|
||||
class="zoaiodol"
|
||||
:item-key="(item) => item"
|
||||
:class="$style.root"
|
||||
animation="150"
|
||||
delay="100"
|
||||
@end="save"
|
||||
delay-on-touch-only="true"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<button
|
||||
class="_button item"
|
||||
@click="remove(element, $event)"
|
||||
>
|
||||
<MkEmoji
|
||||
:emoji="element"
|
||||
style="height: 1.7em"
|
||||
class="emoji"
|
||||
/>
|
||||
</button>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button class="_button add" @click="chooseEmoji">
|
||||
<i class="ph-plus ph-bold ph-lg"></i>
|
||||
</button>
|
||||
</template>
|
||||
</XDraggable>
|
||||
<div
|
||||
v-for="item in reactions"
|
||||
:key="item"
|
||||
class="_button item"
|
||||
@click="remove(item, $event)"
|
||||
>
|
||||
<MkEmoji
|
||||
:emoji="item"
|
||||
style="height: 1.7em"
|
||||
class="emoji"
|
||||
/>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
<button class="_button add" @click="chooseEmoji">
|
||||
<i class="ph-plus ph-bold ph-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
<template #caption
|
||||
>{{ i18n.ts.reactionSettingDescription2 }}
|
||||
|
@ -85,7 +83,7 @@
|
|||
<option :value="1">{{ i18n.ts.small }}</option>
|
||||
<option :value="2">{{ i18n.ts.medium }}</option>
|
||||
<option :value="3">{{ i18n.ts.large }}</option>
|
||||
<option :value="4">{{ i18n.ts.large }}+</option>
|
||||
<option :value="4">{{ i18n.ts.xl }}</option>
|
||||
</FormRadios>
|
||||
|
||||
<FormSwitch
|
||||
|
@ -124,8 +122,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, watch } from "vue";
|
||||
import XDraggable from "vuedraggable";
|
||||
import FormInput from "@/components/form/input.vue";
|
||||
import { VueDraggable } from "vue-draggable-plus";
|
||||
import FormRadios from "@/components/form/radios.vue";
|
||||
import FromSlot from "@/components/form/slot.vue";
|
||||
import FormButton from "@/components/MkButton.vue";
|
||||
|
@ -184,6 +181,7 @@ function remove(reaction, ev: MouseEvent) {
|
|||
text: i18n.ts.remove,
|
||||
action: () => {
|
||||
reactions = reactions.filter((x) => x !== reaction);
|
||||
save();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -221,20 +219,11 @@ function chooseEmoji(ev: MouseEvent) {
|
|||
}).then((emoji) => {
|
||||
if (!reactions.includes(emoji)) {
|
||||
reactions.push(emoji);
|
||||
save();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
$$(reactions),
|
||||
() => {
|
||||
save();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(enableEmojiReactions, async () => {
|
||||
await reloadAsk();
|
||||
});
|
||||
|
@ -253,15 +242,11 @@ const headerTabs = $computed(() => []);
|
|||
definePageMetadata({
|
||||
title: i18n.ts.reaction,
|
||||
icon: "ph-smiley ph-bold ph-lg",
|
||||
action: {
|
||||
icon: "ph-eye ph-bold ph-lg",
|
||||
handler: preview,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.zoaiodol {
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
padding: 12px;
|
||||
font-size: 1.1em;
|
||||
|
||||
|
@ -270,10 +255,12 @@ definePageMetadata({
|
|||
padding: 8px;
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
|
||||
> .add {
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
}
|
||||
.add {
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
margin-left: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, onMounted } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import XNotes from "@/components/MkNotes.vue";
|
||||
import XUserList from "@/components/MkUserList.vue";
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, onMounted } from "vue";
|
||||
import { Virtual } from "swiper";
|
||||
import { Virtual } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import XTutorial from "@/components/MkTutorialDialog.vue";
|
||||
import XTimeline from "@/components/MkTimeline.vue";
|
||||
|
|
|
@ -26,12 +26,13 @@
|
|||
class="banner"
|
||||
:style="{
|
||||
backgroundImage: `url('${user.bannerUrl}')`,
|
||||
'--backgroundImageStatic': defaultStore
|
||||
.state.useBlurEffect && user.bannerUrl
|
||||
? `url('${getStaticImageUrl(
|
||||
user.bannerUrl,
|
||||
)}')`
|
||||
: null,
|
||||
'--backgroundImageStatic':
|
||||
defaultStore.state.useBlurEffect &&
|
||||
user.bannerUrl
|
||||
? `url('${getStaticImageUrl(
|
||||
user.bannerUrl,
|
||||
)}')`
|
||||
: null,
|
||||
}"
|
||||
></div>
|
||||
<div class="fade"></div>
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { getBlurHashAverageColor } from "fast-blurhash";
|
||||
|
||||
function rgbToHex(rgb: number[]): string {
|
||||
return `#${rgb
|
||||
.map((x) => {
|
||||
const hex = x.toString(16);
|
||||
return hex.length === 1 ? `0${hex}` : hex;
|
||||
})
|
||||
.join("")}`;
|
||||
}
|
||||
|
||||
export function extractAvgColorFromBlurhash(hash: string) {
|
||||
return typeof hash === "string"
|
||||
? `#${[...hash.slice(2, 6)]
|
||||
.map((x) =>
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".indexOf(
|
||||
x,
|
||||
),
|
||||
)
|
||||
.reduce((a, c) => a * 83 + c, 0)
|
||||
.toString(16)
|
||||
.padStart(6, "0")}`
|
||||
? rgbToHex(getBlurHashAverageColor(hash))
|
||||
: undefined;
|
||||
}
|
||||
|
|
|
@ -145,8 +145,11 @@ a {
|
|||
cursor: pointer;
|
||||
color: inherit;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: transparent;
|
||||
transition: text-decoration-color 0.2s;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -632,24 +635,26 @@ hr {
|
|||
._link {
|
||||
position: relative;
|
||||
color: var(--link);
|
||||
text-decoration: none !important;
|
||||
text-underline-offset: 0.2em;
|
||||
|
||||
&::before, &::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 0%;
|
||||
border-bottom: 1px solid var(--link);
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
&::before {
|
||||
width: 100%;
|
||||
opacity: .4;
|
||||
}
|
||||
&:hover:after, &:focus:after {
|
||||
width: 100%;
|
||||
}
|
||||
// &::before,
|
||||
// &::after {
|
||||
// content: "";
|
||||
// position: absolute;
|
||||
// bottom: 0;
|
||||
// left: 0;
|
||||
// width: 0%;
|
||||
// border-bottom: 1px solid currentColor;
|
||||
// transition: 0.3s ease-in-out;
|
||||
// }
|
||||
// &::before {
|
||||
// width: 100%;
|
||||
// opacity: 0.4;
|
||||
// }
|
||||
// &:hover:after,
|
||||
// &:focus:after {
|
||||
// width: 100%;
|
||||
// }
|
||||
}
|
||||
|
||||
._caption {
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<MkA
|
||||
v-click-anime
|
||||
v-tooltip.noDelay.right="i18n.ts.timeline"
|
||||
class="nav-item index"
|
||||
class="item index"
|
||||
active-class="active"
|
||||
to="/"
|
||||
exact
|
||||
|
@ -46,7 +46,7 @@
|
|||
v-tooltip.noDelay.right="
|
||||
i18n.ts[navbarItemDef[item].title]
|
||||
"
|
||||
class="nav-item _button"
|
||||
class="item _button"
|
||||
:class="[item, { active: navbarItemDef[item].active }]"
|
||||
active-class="active"
|
||||
:to="navbarItemDef[item].to"
|
||||
|
@ -66,9 +66,6 @@
|
|||
<span
|
||||
v-if="navbarItemDef[item].indicated"
|
||||
class="indicator"
|
||||
:class="{
|
||||
animateIndicator: $store.state.animation,
|
||||
}"
|
||||
><i class="icon ph-circle ph-fill"></i
|
||||
></span>
|
||||
</component>
|
||||
|
@ -78,7 +75,7 @@
|
|||
v-if="$i.isAdmin || $i.isModerator"
|
||||
v-click-anime
|
||||
v-tooltip.noDelay.right="i18n.ts.controlPanel"
|
||||
class="nav-item _button"
|
||||
class="item _button"
|
||||
active-class="active"
|
||||
to="/admin"
|
||||
>
|
||||
|
@ -91,7 +88,6 @@
|
|||
updateAvailable
|
||||
"
|
||||
class="indicator"
|
||||
:class="{ animateIndicator: $store.state.animation }"
|
||||
></span
|
||||
><i class="icon ph-door ph-bold ph-fw ph-lg"></i
|
||||
><span class="text">{{ i18n.ts.controlPanel }}</span>
|
||||
|
@ -99,24 +95,21 @@
|
|||
<button
|
||||
v-click-anime
|
||||
v-tooltip.noDelay.right="i18n.ts.more"
|
||||
class="nav-item _button"
|
||||
class="item _button"
|
||||
@click="more"
|
||||
>
|
||||
<i
|
||||
class="icon ph-dots-three-outline ph-bold ph-fw ph-lg"
|
||||
></i
|
||||
><span class="text">{{ i18n.ts.more }}</span>
|
||||
<span
|
||||
v-if="otherMenuItemIndicated"
|
||||
class="indicator"
|
||||
:class="{ animateIndicator: $store.state.animation }"
|
||||
<span v-if="otherMenuItemIndicated" class="indicator"
|
||||
><i class="icon ph-circle ph-fill"></i
|
||||
></span>
|
||||
</button>
|
||||
<MkA
|
||||
v-click-anime
|
||||
v-tooltip.noDelay.right="i18n.ts.settings"
|
||||
class="nav-item _button"
|
||||
class="item _button"
|
||||
active-class="active"
|
||||
to="/settings"
|
||||
>
|
||||
|
@ -127,7 +120,7 @@
|
|||
<div class="bottom">
|
||||
<button
|
||||
v-tooltip.noDelay.right="i18n.ts.note"
|
||||
class="nav-item _button post"
|
||||
class="item _button post"
|
||||
data-cy-open-post-form
|
||||
@click="os.post"
|
||||
>
|
||||
|
@ -272,125 +265,6 @@ function more(ev: MouseEvent) {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-inline: 30px;
|
||||
line-height: 2.85rem;
|
||||
margin-bottom: 0.5rem;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
color: var(--navFg);
|
||||
|
||||
&:before, &.post::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: calc(100% - 34px);
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 999px;
|
||||
background: var(--accentedBg);
|
||||
opacity: 0;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
position: relative;
|
||||
width: 32px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
> .indicator {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
> .animateIndicator {
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
> .text {
|
||||
position: relative;
|
||||
font-size: 0.9em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
text-decoration: none;
|
||||
color: var(--navHoverFg);
|
||||
transition: color 0.4s ease;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--navActive);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within,
|
||||
&.active {
|
||||
color: var(--accent);
|
||||
opacity: 1;
|
||||
transition: color 0.4s, opacity 0.4s;
|
||||
&::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.post {
|
||||
padding-inline: 0;
|
||||
color: var(--fgOnAccent);
|
||||
font-weight: bold;
|
||||
|
||||
&::before {
|
||||
opacity: 1;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--buttonGradateA),
|
||||
var(--buttonGradateB)
|
||||
);
|
||||
}
|
||||
&::after {
|
||||
background: var(--accentLighten) !important;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within,
|
||||
&.active {
|
||||
&::after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
> .icon,
|
||||
> .text {
|
||||
position: relative;
|
||||
left: 3rem;
|
||||
margin: 0;
|
||||
width: auto;
|
||||
color: var(--fgOnAccent);
|
||||
transform: translateY(0em);
|
||||
}
|
||||
|
||||
> .text {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.iconOnly) {
|
||||
> .body {
|
||||
margin-left: -200px;
|
||||
|
@ -431,6 +305,57 @@ function more(ev: MouseEvent) {
|
|||
> .bottom {
|
||||
padding: 20px 0;
|
||||
|
||||
> .post {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
color: var(--fgOnAccent);
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: calc(100% - 38px);
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--buttonGradateA),
|
||||
var(--buttonGradateB)
|
||||
);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within,
|
||||
&.active {
|
||||
&:before {
|
||||
background: var(--accentLighten);
|
||||
transition: all 0.4s ease;
|
||||
}
|
||||
}
|
||||
|
||||
> .icon,
|
||||
> .text {
|
||||
position: relative;
|
||||
left: 3rem;
|
||||
color: var(--fgOnAccent);
|
||||
transform: translateY(0em);
|
||||
}
|
||||
|
||||
> .text {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
> .instance {
|
||||
position: relative;
|
||||
display: block;
|
||||
|
@ -468,6 +393,75 @@ function more(ev: MouseEvent) {
|
|||
margin: 16px 16px;
|
||||
border-top: solid 0.5px var(--divider);
|
||||
}
|
||||
|
||||
> .item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 30px;
|
||||
line-height: 2.85rem;
|
||||
margin-bottom: 0.5rem;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
color: var(--navFg);
|
||||
|
||||
> .icon {
|
||||
position: relative;
|
||||
width: 32px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
> .indicator {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
> .text {
|
||||
position: relative;
|
||||
font-size: 0.9em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
text-decoration: none;
|
||||
color: var(--navHoverFg);
|
||||
transition: all 0.4s ease;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--navActive);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within,
|
||||
&.active {
|
||||
color: var(--accent);
|
||||
transition: all 0.4s ease;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: calc(100% - 34px);
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 999px;
|
||||
background: var(--accentedBg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -499,6 +493,52 @@ function more(ev: MouseEvent) {
|
|||
> .bottom {
|
||||
padding: 20px 0;
|
||||
|
||||
> .post {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 52px;
|
||||
margin-bottom: 16px;
|
||||
text-align: center;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
width: 52px;
|
||||
aspect-ratio: 1/1;
|
||||
border-radius: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--buttonGradateA),
|
||||
var(--buttonGradateB)
|
||||
);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-within,
|
||||
&.active {
|
||||
&:before {
|
||||
background: var(--accentLighten);
|
||||
transition: all 0.4s ease;
|
||||
}
|
||||
}
|
||||
|
||||
> .icon {
|
||||
position: relative;
|
||||
color: var(--fgOnAccent);
|
||||
}
|
||||
|
||||
> .text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
> .help {
|
||||
position: relative;
|
||||
display: block;
|
||||
|
@ -537,56 +577,67 @@ function more(ev: MouseEvent) {
|
|||
border-top: solid 0.5px var(--divider);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.nav-item {
|
||||
padding: 1.1rem 0;
|
||||
margin-bottom: 0.2rem;
|
||||
text-align: center;
|
||||
> .item {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 1.1rem 0;
|
||||
margin-bottom: 0.2rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
> .icon {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
opacity: 0.7;
|
||||
transform: translateY(0em);
|
||||
}
|
||||
> .icon {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
opacity: 0.7;
|
||||
transform: translateY(0em);
|
||||
}
|
||||
|
||||
> .text {
|
||||
display: none;
|
||||
}
|
||||
> .text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .indicator {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 24px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
}
|
||||
> .indicator {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 24px;
|
||||
color: var(--navIndicator);
|
||||
font-size: 8px;
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
> .animateIndicator {
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
}
|
||||
.post {
|
||||
width: 100%;
|
||||
height: 52px;
|
||||
margin-bottom: 16px;
|
||||
&:before, &::after {
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
width: 52px;
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
> .icon {
|
||||
left: unset;
|
||||
}
|
||||
> .text {
|
||||
display: none;
|
||||
&:hover,
|
||||
&:focus-within,
|
||||
&.active {
|
||||
text-decoration: none;
|
||||
color: var(--accent);
|
||||
transition: all 0.4s ease;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 100%;
|
||||
aspect-ratio: 1;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 999px;
|
||||
background: var(--accentedBg);
|
||||
}
|
||||
|
||||
> .icon,
|
||||
> .text {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
.item {
|
||||
outline: none;
|
||||
&:focus-visible:before {
|
||||
outline: auto;
|
||||
|
|
|
@ -23,9 +23,9 @@ const extensions = [
|
|||
];
|
||||
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
fs.mkdirSync(__dirname + "/../../built", { recursive: true });
|
||||
fs.mkdirSync(`${__dirname}/../../built`, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
__dirname + "/../../built/meta.json",
|
||||
`${__dirname}/../../built/meta.json`,
|
||||
JSON.stringify({ version: meta.version }),
|
||||
"utf-8",
|
||||
);
|
||||
|
@ -40,15 +40,16 @@ export default defineConfig(({ command, mode }) => {
|
|||
pluginJson5(),
|
||||
viteCompression({
|
||||
algorithm: "brotliCompress",
|
||||
verbose: false,
|
||||
}),
|
||||
],
|
||||
|
||||
resolve: {
|
||||
extensions,
|
||||
alias: {
|
||||
"@/": __dirname + "/src/",
|
||||
"/client-assets/": __dirname + "/assets/",
|
||||
"/static-assets/": __dirname + "/../backend/assets/",
|
||||
"@/": `${__dirname}/src/`,
|
||||
"/client-assets/": `${__dirname}/assets/`,
|
||||
"/static-assets/": `${__dirname}/../backend/assets/`,
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -82,7 +83,7 @@ export default defineConfig(({ command, mode }) => {
|
|||
},
|
||||
cssCodeSplit: true,
|
||||
assetsInlineLimit: 0,
|
||||
outDir: __dirname + "/../../built/_client_dist_",
|
||||
outDir: `${__dirname}/../../built/_client_dist_`,
|
||||
assetsDir: ".",
|
||||
emptyOutDir: false,
|
||||
sourcemap: process.env.NODE_ENV === "development",
|
||||
|
@ -94,5 +95,7 @@ export default defineConfig(({ command, mode }) => {
|
|||
optimizeDeps: {
|
||||
auto: true,
|
||||
},
|
||||
|
||||
logLevel: "warn",
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1541,7 +1541,7 @@ export default class Misskey implements MegalodonInterface {
|
|||
if (!res.data || (res.data != 'public' && res.data != 'home' && res.data != 'followers' && res.data != 'specified'))
|
||||
return 'public';
|
||||
return this.converter.visibility(res.data);
|
||||
});
|
||||
}).catch(_ => 'public')
|
||||
}
|
||||
|
||||
public async unfavouriteStatus(id: string): Promise<Response<Entity.Status>> {
|
||||
|
|
|
@ -156,7 +156,7 @@ namespace MisskeyAPI {
|
|||
id: u.id,
|
||||
username: u.username,
|
||||
acct: acct,
|
||||
display_name: u.name,
|
||||
display_name: u.name || u.username,
|
||||
locked: u.isLocked,
|
||||
created_at: u.createdAt,
|
||||
followers_count: u.followersCount,
|
||||
|
|
|
@ -86,6 +86,13 @@
|
|||
"@irfan@calckey.social",
|
||||
"@dvd@dvd.chat",
|
||||
"@charlie2alpha@electricrequiem.com",
|
||||
"@arndot@layer8.space",
|
||||
"@ryan@c.ryanccn.dev",
|
||||
"@lapastora_deprova@calckey.social",
|
||||
"@rameez@calckey.social",
|
||||
"@dracoling@firetribe.org",
|
||||
"@Space6host@calckey.social",
|
||||
"@zakalwe@plasmatrap.com",
|
||||
"\nInterkosmos Link"
|
||||
]
|
||||
}
|
||||
|
|
1679
pnpm-lock.yaml
1679
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue