Merge branch 'develop' of codeberg.org:calckey/calckey into develop
This commit is contained in:
commit
088ff4c251
12
CALCKEY.md
12
CALCKEY.md
|
@ -11,7 +11,7 @@
|
||||||
- Federate with note edits
|
- Federate with note edits
|
||||||
- User "choices" (recommended users) like Mastodon and Soapbox
|
- User "choices" (recommended users) like Mastodon and Soapbox
|
||||||
- Join Reason system like Mastodon/Pleroma
|
- Join Reason system like Mastodon/Pleroma
|
||||||
- Option to publicize instance blocks
|
- Option to publicize server blocks
|
||||||
- Build flag to remove NSFW/AI stuff
|
- Build flag to remove NSFW/AI stuff
|
||||||
- Filter notifications by user
|
- Filter notifications by user
|
||||||
- Exclude self from antenna
|
- Exclude self from antenna
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
- MFM button
|
- MFM button
|
||||||
- Personal notes for all accounts
|
- Personal notes for all accounts
|
||||||
- Fully revamp non-logged-in screen
|
- Fully revamp non-logged-in screen
|
||||||
- Lookup/details for post/file/instance
|
- Lookup/details for post/file/server
|
||||||
- [Rat mode?](https://stop.voring.me/notes/933fx97bmd)
|
- [Rat mode?](https://stop.voring.me/notes/933fx97bmd)
|
||||||
|
|
||||||
## Work in progress
|
## Work in progress
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
- Upgrade packages with security vunrabilities
|
- Upgrade packages with security vunrabilities
|
||||||
- Saner defaults
|
- Saner defaults
|
||||||
- Fediverse account migration
|
- Fediverse account migration
|
||||||
- Recommended instances timeline
|
- Recommended servers timeline
|
||||||
- OCR image captioning
|
- OCR image captioning
|
||||||
- Improve mobile UX
|
- Improve mobile UX
|
||||||
- Swipe through pages on mobile
|
- Swipe through pages on mobile
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
- Better welcome screen (not logged in)
|
- Better welcome screen (not logged in)
|
||||||
- vue-plyr as video/audio player
|
- vue-plyr as video/audio player
|
||||||
- Ability to turn off "Connection lost" message
|
- Ability to turn off "Connection lost" message
|
||||||
- Raw instance info only for moderators
|
- Raw server info only for moderators
|
||||||
- New spinner animation
|
- New spinner animation
|
||||||
- Spinner instead of "Loading..."
|
- Spinner instead of "Loading..."
|
||||||
- SearchX instead of Google
|
- SearchX instead of Google
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
- Obliteration of Ai-chan
|
- Obliteration of Ai-chan
|
||||||
- Switch to [Calckey.js](https://codeberg.org/calckey/calckey.js)
|
- Switch to [Calckey.js](https://codeberg.org/calckey/calckey.js)
|
||||||
- Woozy mode 🥴
|
- Woozy mode 🥴
|
||||||
- Improve blocking instances
|
- Improve blocking servers
|
||||||
- Release notes
|
- Release notes
|
||||||
- New post style
|
- New post style
|
||||||
- Admins set default reaction emoji
|
- Admins set default reaction emoji
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
- Sonic search
|
- Sonic search
|
||||||
- Popular color schemes, including Nord, Gruvbox, and Catppuccin
|
- Popular color schemes, including Nord, Gruvbox, and Catppuccin
|
||||||
- Non-nyaify cat mode
|
- Non-nyaify cat mode
|
||||||
- Post imports from other Calckey/Misskey/Mastodon/Pleroma/Akkoma instances
|
- Post imports from other Calckey/Misskey/Mastodon/Pleroma/Akkoma servers
|
||||||
- Improve Classic mode
|
- Improve Classic mode
|
||||||
- Proper Helm/Kubernetes config
|
- Proper Helm/Kubernetes config
|
||||||
- Multiple boost visibilities
|
- Multiple boost visibilities
|
||||||
|
|
18
README.md
18
README.md
|
@ -23,15 +23,15 @@
|
||||||
# ✨ About Calckey
|
# ✨ About Calckey
|
||||||
|
|
||||||
- Calckey is based off of Misskey, a powerful microblogging server on ActivityPub with features such as emoji reactions, a customizable web UI, rich chatting, and much more!
|
- Calckey is based off of Misskey, a powerful microblogging server on ActivityPub with features such as emoji reactions, a customizable web UI, rich chatting, and much more!
|
||||||
- Calckey adds many quality of life changes and bug fixes for users and instance admins alike.
|
- Calckey adds many quality of life changes and bug fixes for users and server admins alike.
|
||||||
- Read **[this document](./CALCKEY.md)** all for current and future differences.
|
- Read **[this document](./CALCKEY.md)** all for current and future differences.
|
||||||
- Notable differences:
|
- Notable differences:
|
||||||
- Improved UI/UX (especially on mobile)
|
- Improved UI/UX (especially on mobile)
|
||||||
- Improved notifications
|
- Improved notifications
|
||||||
- Improved instance security
|
- Improved server security
|
||||||
- Improved accessibility
|
- Improved accessibility
|
||||||
- Improved threads
|
- Improved threads
|
||||||
- Recommended Instances timeline
|
- Recommended Servers timeline
|
||||||
- OCR image captioning
|
- OCR image captioning
|
||||||
- New and improved Groups
|
- New and improved Groups
|
||||||
- Better intro tutorial
|
- Better intro tutorial
|
||||||
|
@ -50,10 +50,10 @@
|
||||||
- 💸 OpenCollective: <https://opencollective.com/Calckey>
|
- 💸 OpenCollective: <https://opencollective.com/Calckey>
|
||||||
- 💸 Liberapay: <https://liberapay.com/ThatOneCalculator>
|
- 💸 Liberapay: <https://liberapay.com/ThatOneCalculator>
|
||||||
- Donate publicly to get your name on the Patron list!
|
- Donate publicly to get your name on the Patron list!
|
||||||
- 🚢 Flagship instance: <https://calckey.social>
|
- 🚢 Flagship server: <https://calckey.social>
|
||||||
- 📣 Official account: <https://i.calckey.cloud/@calckey>
|
- 📣 Official account: <https://i.calckey.cloud/@calckey>
|
||||||
- 💁 Matrix support room: <https://matrix.to/#/#calckey:matrix.fedibird.com>
|
- 💁 Matrix support room: <https://matrix.to/#/#calckey:matrix.fedibird.com>
|
||||||
- 📜 Instance list: <https://calckey.fediverse.observer/list>
|
- 📜 Server list: <https://calckey.fediverse.observer/list>
|
||||||
- 📖 JoinFediverse Wiki: <https://joinfediverse.wiki/What_is_Calckey%3F>
|
- 📖 JoinFediverse Wiki: <https://joinfediverse.wiki/What_is_Calckey%3F>
|
||||||
- 🐋 Docker Hub: <https://hub.docker.com/r/thatonecalculator/calckey>
|
- 🐋 Docker Hub: <https://hub.docker.com/r/thatonecalculator/calckey>
|
||||||
- ✍️ Weblate: <https://hosted.weblate.org/engage/calckey/>
|
- ✍️ Weblate: <https://hosted.weblate.org/engage/calckey/>
|
||||||
|
@ -177,13 +177,13 @@ Please don't use ElasticSearch unless you already have an ElasticSearch setup an
|
||||||
## 💅 Customize
|
## 💅 Customize
|
||||||
|
|
||||||
- To add custom CSS for all users, edit `./custom/assets/instance.css`.
|
- To add custom CSS for all users, edit `./custom/assets/instance.css`.
|
||||||
- To add static assets (such as images for the splash screen), place them in the `./custom/assets/` directory. They'll then be available on `https://yourinstance.tld/static-assets/filename.ext`.
|
- To add static assets (such as images for the splash screen), place them in the `./custom/assets/` directory. They'll then be available on `https://yourserver.tld/static-assets/filename.ext`.
|
||||||
- To add custom locales, place them in the `./custom/locales/` directory. If you name your custom locale the same as an existing locale, it will overwrite it. If you give it a unique name, it will be added to the list. Also make sure that the first part of the filename matches the locale you're basing it on. (Example: `en-FOO.yml`)
|
- To add custom locales, place them in the `./custom/locales/` directory. If you name your custom locale the same as an existing locale, it will overwrite it. If you give it a unique name, it will be added to the list. Also make sure that the first part of the filename matches the locale you're basing it on. (Example: `en-FOO.yml`)
|
||||||
- To add custom error images, place them in the `./custom/assets/badges` directory, replacing the files already there.
|
- To add custom error images, place them in the `./custom/assets/badges` directory, replacing the files already there.
|
||||||
- To add custom sounds, place only mp3 files in the `./custom/assets/sounds` directory.
|
- To add custom sounds, place only mp3 files in the `./custom/assets/sounds` directory.
|
||||||
- To update custom assets without rebuilding, just run `pnpm run gulp`.
|
- To update custom assets without rebuilding, just run `pnpm run gulp`.
|
||||||
|
|
||||||
## 🧑🔬 Configuring a new instance
|
## 🧑🔬 Configuring a new server
|
||||||
|
|
||||||
- Run `cp .config/example.yml .config/default.yml`
|
- Run `cp .config/example.yml .config/default.yml`
|
||||||
- Edit `.config/default.yml`, making sure to fill out required fields.
|
- Edit `.config/default.yml`, making sure to fill out required fields.
|
||||||
|
@ -198,7 +198,7 @@ For migrating from Misskey v13, Misskey v12, and Foundkey, read [this document](
|
||||||
### 🍀 Nginx (recommended)
|
### 🍀 Nginx (recommended)
|
||||||
|
|
||||||
- Run `sudo cp ./calckey.nginx.conf /etc/nginx/sites-available/ && cd /etc/nginx/sites-available/`
|
- Run `sudo cp ./calckey.nginx.conf /etc/nginx/sites-available/ && cd /etc/nginx/sites-available/`
|
||||||
- Edit `calckey.nginx.conf` to reflect your instance properly
|
- Edit `calckey.nginx.conf` to reflect your server properly
|
||||||
- Run `sudo ln -s ./calckey.nginx.conf ../sites-enabled/calckey.nginx.conf`
|
- Run `sudo ln -s ./calckey.nginx.conf ../sites-enabled/calckey.nginx.conf`
|
||||||
- Run `sudo nginx -t` to validate that the config is valid, then restart the NGINX service.
|
- Run `sudo nginx -t` to validate that the config is valid, then restart the NGINX service.
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ example.tld {
|
||||||
> Apache has some known problems with Calckey. Only use it if you have to.
|
> Apache has some known problems with Calckey. Only use it if you have to.
|
||||||
|
|
||||||
- Run `sudo cp ./calckey.apache.conf /etc/apache2/sites-available/ && cd /etc/apache2/sites-available/`
|
- Run `sudo cp ./calckey.apache.conf /etc/apache2/sites-available/ && cd /etc/apache2/sites-available/`
|
||||||
- Edit `calckey.apache.conf` to reflect your instance properly
|
- Edit `calckey.apache.conf` to reflect your server properly
|
||||||
- Run `sudo a2ensite calckey.apache` to enable the site
|
- Run `sudo a2ensite calckey.apache` to enable the site
|
||||||
- Run `sudo service apache2 restart` to reload apache2 configuration
|
- Run `sudo service apache2 restart` to reload apache2 configuration
|
||||||
## 🚀 Build and launch!
|
## 🚀 Build and launch!
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# 🐳 Running a Calckey instance with Docker
|
# 🐳 Running a Calckey server with Docker
|
||||||
|
|
||||||
## Pre-built docker container
|
## Pre-built docker container
|
||||||
[thatonecalculator/calckey](https://hub.docker.com/r/thatonecalculator/calckey)
|
[thatonecalculator/calckey](https://hub.docker.com/r/thatonecalculator/calckey)
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
There is a `docker-compose.yml` in the root of the project that you can use to build the container from source
|
There is a `docker-compose.yml` in the root of the project that you can use to build the container from source
|
||||||
|
|
||||||
- .config/docker.env (**db config settings**)
|
- .config/docker.env (**db config settings**)
|
||||||
- .config/default.yml (**calckey instance settings**)
|
- .config/default.yml (**calckey server settings**)
|
||||||
|
|
||||||
## Configuring
|
## Configuring
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ Rename the files:
|
||||||
|
|
||||||
then edit them according to your environment.
|
then edit them according to your environment.
|
||||||
You can configure `docker.env` with anything you like, but you will have to pay attention to the `default.yml` file:
|
You can configure `docker.env` with anything you like, but you will have to pay attention to the `default.yml` file:
|
||||||
- `url` should be set to the URL you will be hosting the web interface for the instance at.
|
- `url` should be set to the URL you will be hosting the web interface for the server at.
|
||||||
- `host`, `db`, `user`, `pass` will have to be configured in the `PostgreSQL configuration` section - `host` is the name of the postgres container (eg: *calckey_db_1*), and the others should match your `docker.env`.
|
- `host`, `db`, `user`, `pass` will have to be configured in the `PostgreSQL configuration` section - `host` is the name of the postgres container (eg: *calckey_db_1*), and the others should match your `docker.env`.
|
||||||
- `host`will need to be configured in the *Redis configuration* section - it is the name of the redis container (eg: *calckey_redis_1*)
|
- `host`will need to be configured in the *Redis configuration* section - it is the name of the redis container (eg: *calckey_redis_1*)
|
||||||
- `auth` will need to be configured in the *Sonic* section - cannot be the default `SecretPassword`
|
- `auth` will need to be configured in the *Sonic* section - cannot be the default `SecretPassword`
|
||||||
|
@ -36,7 +36,7 @@ Copy `docker-compose.yml` and the `config/` to a directory, then run the **docke
|
||||||
|
|
||||||
NOTE: This will take some time to come fully online, even after download and extracting the container images, and it may emit some error messages before completing successfully. Specifically, the `db` container needs to initialize and so isn't available to the `web` container right away. Only once the `db` container comes online does the `web` container start building and initializing the calckey tables.
|
NOTE: This will take some time to come fully online, even after download and extracting the container images, and it may emit some error messages before completing successfully. Specifically, the `db` container needs to initialize and so isn't available to the `web` container right away. Only once the `db` container comes online does the `web` container start building and initializing the calckey tables.
|
||||||
|
|
||||||
Once the instance is up you can use a web browser to access the web interface at `http://serverip:3000` (where `serverip` is the IP of the server you are running the calckey instance on).
|
Once the server is up you can use a web browser to access the web interface at `http://serverip:3000` (where `serverip` is the IP of the server you are running the calckey server on).
|
||||||
|
|
||||||
## Docker for development
|
## Docker for development
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Running a Calckey instance with Kubernetes and Helm
|
# Running a Calckey server with Kubernetes and Helm
|
||||||
|
|
||||||
This is a [Helm](https://helm.sh/) chart directory in the root of the project
|
This is a [Helm](https://helm.sh/) chart directory in the root of the project
|
||||||
that you can use to deploy calckey to a Kubernetes cluster
|
that you can use to deploy calckey to a Kubernetes cluster
|
||||||
|
@ -27,7 +27,7 @@ helm upgrade \
|
||||||
-f .config/helm_values.yml
|
-f .config/helm_values.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Watch your calckey instance spin up:
|
4. Watch your calckey server spin up:
|
||||||
```shell
|
```shell
|
||||||
kubectl -n calckey get po -w
|
kubectl -n calckey get po -w
|
||||||
```
|
```
|
||||||
|
|
|
@ -598,6 +598,8 @@ scratchpadDescription: "The scratchpad provides an environment for AiScript expe
|
||||||
output: "Output"
|
output: "Output"
|
||||||
script: "Script"
|
script: "Script"
|
||||||
disablePagesScript: "Disable AiScript on Pages"
|
disablePagesScript: "Disable AiScript on Pages"
|
||||||
|
expandOnNoteClick: "Open post on click"
|
||||||
|
expandOnNoteClickDesc: "If disabled, you can still open posts in the right-click menu or by clicking the timestamp."
|
||||||
updateRemoteUser: "Update remote user information"
|
updateRemoteUser: "Update remote user information"
|
||||||
deleteAllFiles: "Delete all files"
|
deleteAllFiles: "Delete all files"
|
||||||
deleteAllFilesConfirm: "Are you sure that you want to delete all files?"
|
deleteAllFilesConfirm: "Are you sure that you want to delete all files?"
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { addFile } from "@/services/drive/add-file.js";
|
||||||
import { genId } from "@/misc/gen-id.js";
|
import { genId } from "@/misc/gen-id.js";
|
||||||
import { db } from "@/db/postgre.js";
|
import { db } from "@/db/postgre.js";
|
||||||
import probeImageSize from "probe-image-size";
|
import probeImageSize from "probe-image-size";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
const logger = queueLogger.createSubLogger("import-custom-emojis");
|
const logger = queueLogger.createSubLogger("import-custom-emojis");
|
||||||
|
|
||||||
|
@ -29,11 +30,11 @@ export async function importCustomEmojis(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [path, cleanup] = await createTempDir();
|
const [tempPath, cleanup] = await createTempDir();
|
||||||
|
|
||||||
logger.info(`Temp dir is ${path}`);
|
logger.info(`Temp dir is ${tempPath}`);
|
||||||
|
|
||||||
const destPath = `${path}/emojis.zip`;
|
const destPath = `${tempPath}/emojis.zip`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(destPath, "", "binary");
|
fs.writeFileSync(destPath, "", "binary");
|
||||||
|
@ -46,44 +47,96 @@ export async function importCustomEmojis(
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputPath = `${path}/emojis`;
|
const outputPath = `${tempPath}/emojis`;
|
||||||
const unzipStream = fs.createReadStream(destPath);
|
const unzipStream = fs.createReadStream(destPath);
|
||||||
const zip = new AdmZip(destPath);
|
const zip = new AdmZip(destPath);
|
||||||
zip.extractAllToAsync(outputPath, true, false, async (error) => {
|
zip.extractAllToAsync(outputPath, true, false, async (error) => {
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
const metaRaw = fs.readFileSync(`${outputPath}/meta.json`, "utf-8");
|
|
||||||
const meta = JSON.parse(metaRaw);
|
|
||||||
|
|
||||||
for (const record of meta.emojis) {
|
if (fs.existsSync(`${outputPath}/meta.json`)) {
|
||||||
if (!record.downloaded) continue;
|
logger.info("starting emoji import with metadata");
|
||||||
const emojiInfo = record.emoji;
|
const metaRaw = fs.readFileSync(`${outputPath}/meta.json`, "utf-8");
|
||||||
const emojiPath = `${outputPath}/${record.fileName}`;
|
const meta = JSON.parse(metaRaw);
|
||||||
await Emojis.delete({
|
|
||||||
name: emojiInfo.name,
|
for (const record of meta.emojis) {
|
||||||
});
|
if (!record.downloaded) continue;
|
||||||
const driveFile = await addFile({
|
const emojiInfo = record.emoji;
|
||||||
user: null,
|
const emojiPath = `${outputPath}/${record.fileName}`;
|
||||||
path: emojiPath,
|
await Emojis.delete({
|
||||||
name: record.fileName,
|
name: emojiInfo.name,
|
||||||
force: true,
|
});
|
||||||
});
|
const driveFile = await addFile({
|
||||||
const file = fs.createReadStream(emojiPath);
|
user: null,
|
||||||
const size = await probeImageSize(file);
|
path: emojiPath,
|
||||||
file.destroy();
|
name: record.fileName,
|
||||||
await Emojis.insert({
|
force: true,
|
||||||
id: genId(),
|
});
|
||||||
updatedAt: new Date(),
|
const file = fs.createReadStream(emojiPath);
|
||||||
name: emojiInfo.name,
|
const size = await probeImageSize(file);
|
||||||
category: emojiInfo.category,
|
file.destroy();
|
||||||
host: null,
|
await Emojis.insert({
|
||||||
aliases: emojiInfo.aliases,
|
id: genId(),
|
||||||
originalUrl: driveFile.url,
|
updatedAt: new Date(),
|
||||||
publicUrl: driveFile.webpublicUrl ?? driveFile.url,
|
name: emojiInfo.name,
|
||||||
type: driveFile.webpublicType ?? driveFile.type,
|
category: emojiInfo.category,
|
||||||
license: emojiInfo.license,
|
host: null,
|
||||||
width: size.width || null,
|
aliases: emojiInfo.aliases,
|
||||||
height: size.height || null,
|
originalUrl: driveFile.url,
|
||||||
}).then((x) => Emojis.findOneByOrFail(x.identifiers[0]));
|
publicUrl: driveFile.webpublicUrl ?? driveFile.url,
|
||||||
|
type: driveFile.webpublicType ?? driveFile.type,
|
||||||
|
license: emojiInfo.license,
|
||||||
|
width: size.width || null,
|
||||||
|
height: size.height || null,
|
||||||
|
}).then((x) => Emojis.findOneByOrFail(x.identifiers[0]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("starting emoji import without metadata");
|
||||||
|
// Since we lack metadata, we import into a randomized category name instead
|
||||||
|
let categoryName = genId();
|
||||||
|
|
||||||
|
let containedEmojis = fs.readdirSync(outputPath);
|
||||||
|
|
||||||
|
// Filter out accidental JSON files
|
||||||
|
containedEmojis = containedEmojis.filter(
|
||||||
|
(emoji) => !emoji.match(/\.(json)$/i),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const emojiFilename of containedEmojis) {
|
||||||
|
// strip extension and get filename to use as name
|
||||||
|
const name = path.basename(emojiFilename, path.extname(emojiFilename));
|
||||||
|
const emojiPath = `${outputPath}/${emojiFilename}`;
|
||||||
|
|
||||||
|
logger.info(`importing ${name}`);
|
||||||
|
|
||||||
|
await Emojis.delete({
|
||||||
|
name: name,
|
||||||
|
});
|
||||||
|
const driveFile = await addFile({
|
||||||
|
user: null,
|
||||||
|
path: emojiPath,
|
||||||
|
name: path.basename(emojiFilename),
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
const file = fs.createReadStream(emojiPath);
|
||||||
|
const size = await probeImageSize(file);
|
||||||
|
file.destroy();
|
||||||
|
logger.info(`emoji size: ${size.width}x${size.height}`);
|
||||||
|
|
||||||
|
await Emojis.insert({
|
||||||
|
id: genId(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
name: name,
|
||||||
|
category: categoryName,
|
||||||
|
host: null,
|
||||||
|
aliases: [],
|
||||||
|
originalUrl: driveFile.url,
|
||||||
|
publicUrl: driveFile.webpublicUrl ?? driveFile.url,
|
||||||
|
type: driveFile.webpublicType ?? driveFile.type,
|
||||||
|
license: null,
|
||||||
|
width: size.width || null,
|
||||||
|
height: size.height || null,
|
||||||
|
}).then((x) => Emojis.findOneByOrFail(x.identifiers[0]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.queryResultCache!.remove(["meta_emojis"]);
|
await db.queryResultCache!.remove(["meta_emojis"]);
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
class="article"
|
class="article"
|
||||||
@contextmenu.stop="onContextmenu"
|
@contextmenu.stop="onContextmenu"
|
||||||
@click="noteClick"
|
@click="noteClick"
|
||||||
|
:style="{ cursor: expandOnNoteClick && !detailedView ? 'pointer' : '' }"
|
||||||
>
|
>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
@ -313,6 +314,7 @@ const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
|
||||||
const translation = ref(null);
|
const translation = ref(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
||||||
|
const expandOnNoteClick = defaultStore.state.expandOnNoteClick;
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
r: () => reply(true),
|
r: () => reply(true),
|
||||||
|
@ -501,7 +503,7 @@ function scrollIntoView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function noteClick(e) {
|
function noteClick(e) {
|
||||||
if (document.getSelection().type === "Range" || props.detailedView) {
|
if (document.getSelection().type === "Range" || props.detailedView || !expandOnNoteClick) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
} else {
|
} else {
|
||||||
router.push(notePage(appearNote));
|
router.push(notePage(appearNote));
|
||||||
|
@ -704,7 +706,6 @@ defineExpose({
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
padding: 4px 32px 10px;
|
padding: 4px 32px 10px;
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:first-child,
|
&:first-child,
|
||||||
&:nth-child(2) {
|
&:nth-child(2) {
|
||||||
|
|
|
@ -534,12 +534,8 @@ onUnmounted(() => {
|
||||||
|
|
||||||
> .reply {
|
> .reply {
|
||||||
border-top: solid 0.5px var(--divider);
|
border-top: solid 0.5px var(--divider);
|
||||||
cursor: pointer;
|
|
||||||
padding-top: 24px;
|
padding-top: 24px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
@media (pointer: coarse) {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hover
|
// Hover
|
||||||
|
|
|
@ -14,7 +14,10 @@
|
||||||
@contextmenu.stop="onContextmenu"
|
@contextmenu.stop="onContextmenu"
|
||||||
>
|
>
|
||||||
<div v-if="conversation && depth > 1" class="line"></div>
|
<div v-if="conversation && depth > 1" class="line"></div>
|
||||||
<div class="main" @click="noteClick">
|
<div class="main"
|
||||||
|
@click="noteClick"
|
||||||
|
:style="{ cursor: expandOnNoteClick ? 'pointer' : '' }"
|
||||||
|
>
|
||||||
<div class="avatar-container">
|
<div class="avatar-container">
|
||||||
<MkAvatar class="avatar" :user="appearNote.user" />
|
<MkAvatar class="avatar" :user="appearNote.user" />
|
||||||
<div
|
<div
|
||||||
|
@ -258,6 +261,7 @@ const replies: misskey.entities.Note[] =
|
||||||
)
|
)
|
||||||
.reverse() ?? [];
|
.reverse() ?? [];
|
||||||
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
const enableEmojiReactions = defaultStore.state.enableEmojiReactions;
|
||||||
|
const expandOnNoteClick = defaultStore.state.expandOnNoteClick;
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
|
@ -397,7 +401,7 @@ function blur() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function noteClick(e) {
|
function noteClick(e) {
|
||||||
if (document.getSelection().type === "Range") {
|
if (document.getSelection().type === "Range" || !expandOnNoteClick) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
} else {
|
} else {
|
||||||
router.push(notePage(props.note));
|
router.push(notePage(props.note));
|
||||||
|
@ -422,7 +426,6 @@ function noteClick(e) {
|
||||||
|
|
||||||
> .main {
|
> .main {
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
> .avatar-container {
|
> .avatar-container {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
|
|
@ -168,10 +168,10 @@
|
||||||
<i class="ph-stop ph-bold"></i> {{ i18n.ts._mfm.stop }}
|
<i class="ph-stop ph-bold"></i> {{ i18n.ts._mfm.stop }}
|
||||||
</template>
|
</template>
|
||||||
</MkButton>
|
</MkButton>
|
||||||
<div
|
<!-- <div
|
||||||
v-if="(isLong && !collapsed) || (props.note.cw && showContent)"
|
v-if="(isLong && !collapsed) || (props.note.cw && showContent)"
|
||||||
class="fade"
|
class="fade"
|
||||||
></div>
|
></div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,10 @@
|
||||||
<FormSwitch v-model="disablePagesScript" class="_formBlock">{{
|
<FormSwitch v-model="disablePagesScript" class="_formBlock">{{
|
||||||
i18n.ts.disablePagesScript
|
i18n.ts.disablePagesScript
|
||||||
}}</FormSwitch>
|
}}</FormSwitch>
|
||||||
|
<FormSwitch v-model="expandOnNoteClick" class="_formBlock">{{
|
||||||
|
i18n.ts.expandOnNoteClick
|
||||||
|
}}<template #caption>{{ i18n.ts.expandOnNoteClickDesc }}</template>
|
||||||
|
</FormSwitch>
|
||||||
<FormSwitch v-model="profile.showTimelineReplies" class="_formBlock"
|
<FormSwitch v-model="profile.showTimelineReplies" class="_formBlock"
|
||||||
>{{ i18n.ts.flagShowTimelineReplies
|
>{{ i18n.ts.flagShowTimelineReplies
|
||||||
}}<template #caption
|
}}<template #caption
|
||||||
|
@ -299,6 +303,9 @@ const nsfw = computed(defaultStore.makeGetterSetter("nsfw"));
|
||||||
const disablePagesScript = computed(
|
const disablePagesScript = computed(
|
||||||
defaultStore.makeGetterSetter("disablePagesScript")
|
defaultStore.makeGetterSetter("disablePagesScript")
|
||||||
);
|
);
|
||||||
|
const expandOnNoteClick = computed(
|
||||||
|
defaultStore.makeGetterSetter("expandOnNoteClick")
|
||||||
|
);
|
||||||
const showFixedPostForm = computed(
|
const showFixedPostForm = computed(
|
||||||
defaultStore.makeGetterSetter("showFixedPostForm")
|
defaultStore.makeGetterSetter("showFixedPostForm")
|
||||||
);
|
);
|
||||||
|
@ -366,6 +373,7 @@ watch(
|
||||||
seperateRenoteQuote,
|
seperateRenoteQuote,
|
||||||
showAdminUpdates,
|
showAdminUpdates,
|
||||||
autoplayMfm,
|
autoplayMfm,
|
||||||
|
expandOnNoteClick,
|
||||||
],
|
],
|
||||||
async () => {
|
async () => {
|
||||||
await reloadAsk();
|
await reloadAsk();
|
||||||
|
|
|
@ -162,6 +162,10 @@ export const defaultStore = markRaw(
|
||||||
where: "device",
|
where: "device",
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
expandOnNoteClick: {
|
||||||
|
where: "device",
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
nsfw: {
|
nsfw: {
|
||||||
where: "device",
|
where: "device",
|
||||||
default: "respect" as "respect" | "force" | "ignore",
|
default: "respect" as "respect" | "force" | "ignore",
|
||||||
|
|
Loading…
Reference in New Issue