Merge commit '97a0127dbf0b96203902fb075b1d51659a921bfc'

Conflicts:
	pnpm-lock.yaml
This commit is contained in:
CGsama 2023-07-16 20:39:26 -04:00
commit 62cc362822
130 changed files with 6630 additions and 4694 deletions

View File

@ -6,19 +6,13 @@
## Planned
- Stucture
- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative
- Optionally use [ScyllaDB](https://www.scylladb.com/open-source-nosql-database/) for storing notes
- Rewrite backend in Rust and [Rocket](https://rocket.rs/)
- Use [Magic RegExP](https://regexp.dev/) for RegEx 🦄
- Function
- User "choices" (recommended users) and featured hashtags like Mastodon and Soapbox
- Join Reason system like Mastodon/Pleroma
- Option to publicize server blocks
- More antenna options
- Groups
- Form
- Lookup/details for post/file/server
- [Rat mode?](https://stop.voring.me/notes/933fx97bmd)
## Work in progress
@ -30,6 +24,7 @@
- Timeline filters
- Events
- Fully revamp non-logged-in screen
- Optionally use [ScyllaDB](https://www.scylladb.com/open-source-nosql-database/) for storing notes
## Implemented
@ -122,6 +117,7 @@
- Let moderators see moderation nodes
- Non-mangled unicode emojis
- Skin tone selection support
- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative
## Implemented (remote)

View File

@ -1,6 +1,6 @@
{
"name": "calckey",
"version": "14.0.0-dev78",
"version": "14.0.0-dev79",
"codename": "aqua",
"repository": {
"type": "git",
@ -57,7 +57,7 @@
"gulp-replace": "1.1.4",
"gulp-terser": "2.1.0",
"install-peers": "^1.0.4",
"rome": "^12.1.3",
"rome": "^v12.1.3-nightly.f65b0d9",
"start-server-and-test": "1.15.2",
"typescript": "5.1.6"
}

View File

@ -1,9 +1,15 @@
export class tweakVarcharLength1678426061773 {
name = 'tweakVarcharLength1678426061773'
name = "tweakVarcharLength1678426061773";
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "smtpUser" TYPE character varying(1024)`, undefined);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "smtpPass" TYPE character varying(1024)`, undefined);
await queryRunner.query(
`ALTER TABLE "meta" ALTER COLUMN "smtpUser" TYPE character varying(1024)`,
undefined,
);
await queryRunner.query(
`ALTER TABLE "meta" ALTER COLUMN "smtpPass" TYPE character varying(1024)`,
undefined,
);
}
async down(queryRunner) {}

View File

@ -43,6 +43,7 @@
"universal": "napi universal",
"version": "napi version",
"format": "cargo fmt --all",
"lint": "cargo clippy --fix",
"cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration",
"cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
"cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"

View File

@ -46,7 +46,7 @@ impl Repository<Antenna> for antenna::Model {
src: self.src.try_into()?,
user_list_id: self.user_list_id,
user_group_id,
users: self.users.into(),
users: self.users,
instances: self.instances.into(),
case_sensitive: self.case_sensitive,
notify: self.notify,

View File

@ -58,7 +58,7 @@ impl TryFrom<AntennaSrcEnum> for super::AntennaSrc {
// ---- TODO: could be macro
impl Schema<Self> for super::Antenna {}
pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| super::Antenna::validator());
pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(super::Antenna::validator);
// ----
cfg_if! {

View File

@ -91,7 +91,7 @@ pub enum AppPermission {
impl Schema<Self> for App {}
pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(|| App::validator());
pub static VALIDATOR: Lazy<JSONSchema> = Lazy::new(App::validator);
#[cfg(test)]
mod unit_test {

View File

@ -148,8 +148,8 @@ async fn setup_model(db: &DbConn) {
let user_model = entity::user::Model {
id: user_id.to_owned(),
created_at: Utc::now().into(),
username: name.to_lowercase().to_string(),
username_lower: name.to_lowercase().to_string(),
username: name.to_lowercase(),
username_lower: name.to_lowercase(),
name: Some(name.to_string()),
token: Some(gen_string(16)),
is_admin: true,

View File

@ -43,18 +43,16 @@ mod int_test {
keywords: vec![
vec!["foo".to_string(), "bar".to_string()],
vec!["foobar".to_string()],
]
.into(),
],
exclude_keywords: vec![
vec!["abc".to_string()],
vec!["def".to_string(), "ghi".to_string()],
]
.into(),
],
src: schema::AntennaSrc::All,
user_list_id: None,
user_group_id: None,
users: vec![].into(),
instances: vec![].into(),
users: vec![],
instances: vec![],
case_sensitive: true,
notify: true,
with_replies: false,

View File

@ -73,6 +73,7 @@
"is-svg": "4.3.2",
"js-yaml": "4.1.0",
"jsdom": "20.0.3",
"json5": "2.2.3",
"jsonld": "8.2.0",
"jsrsasign": "10.8.6",
"koa": "2.14.2",
@ -188,7 +189,6 @@
"cross-env": "7.0.3",
"eslint": "^8.44.0",
"execa": "6.1.0",
"json5": "2.2.3",
"json5-loader": "4.0.1",
"mocha": "10.2.0",
"pug": "3.0.2",

View File

@ -1,5 +1,8 @@
import config from "@/config/index.js";
import { DB_MAX_NOTE_TEXT_LENGTH, DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
import {
DB_MAX_NOTE_TEXT_LENGTH,
DB_MAX_IMAGE_COMMENT_LENGTH,
} from "@/misc/hard-limits.js";
export const MAX_NOTE_TEXT_LENGTH = Math.min(
config.maxNoteLength ?? 3000,

View File

@ -24,6 +24,7 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
.stream(url, {
headers: {
"User-Agent": config.userAgent,
Host: new URL(url).hostname,
},
timeout: {
lookup: timeout,

View File

@ -1,4 +1,6 @@
import * as fs from "node:fs";
import net from "node:net";
import { promises } from "node:dns";
import type Koa from "koa";
import sharp from "sharp";
import type { IImage } from "@/services/drive/image-processor.js";
@ -19,6 +21,40 @@ export async function proxyMedia(ctx: Koa.Context) {
return;
}
const { hostname } = new URL(url);
let resolvedIps;
try {
resolvedIps = await promises.resolve(hostname);
} catch (error) {
ctx.status = 400;
ctx.body = { message: "Invalid URL" };
return;
}
const isSSRF = resolvedIps.some((ip) => {
if (net.isIPv4(ip)) {
const parts = ip.split(".").map(Number);
return (
parts[0] === 10 ||
(parts[0] === 172 && parts[1] >= 16 && parts[1] < 32) ||
(parts[0] === 192 && parts[1] === 168) ||
parts[0] === 127 ||
parts[0] === 0
);
} else if (net.isIPv6(ip)) {
return (
ip.startsWith("::") || ip.startsWith("fc00:") || ip.startsWith("fe80:")
);
}
return false;
});
if (isSSRF) {
ctx.status = 400;
ctx.body = { message: "Access to this URL is not allowed" };
return;
}
// Create temp file
const [path, cleanup] = await createTemp();

View File

@ -0,0 +1,7 @@
{
"extends": ["@eslint-sets/vue3", "@eslint-sets/vue3-ts"],
"plugins": ["file-progress", "prettier"],
"rules": {
"file-progress/activate": 1
}
}

View File

@ -4,11 +4,14 @@
"scripts": {
"watch": "pnpm vite build --watch --mode development",
"build": "pnpm vite build",
"lint": "pnpm rome check \"src/**/*.{ts,vue}\"",
"format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}'"
"lint": "pnpm rome check **/*.ts --apply && pnpm run lint:vue",
"lint:vue": "pnpm paralint --ext .vue --fix '**/*.vue' --cache",
"format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata"
},
"devDependencies": {
"@discordapp/twemoji": "14.1.2",
"@eslint-sets/eslint-config-vue3": "^5.6.1",
"@eslint-sets/eslint-config-vue3-ts": "^3.3.0",
"@phosphor-icons/web": "^2.0.3",
"@rollup/plugin-alias": "3.1.9",
"@rollup/plugin-json": "4.1.0",
@ -46,6 +49,8 @@
"date-fns": "2.30.0",
"emojilib": "github:thatonecalculator/emojilib",
"escape-regexp": "0.0.1",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-file-progress": "^1.3.0",
"eventemitter3": "5.0.1",
"fast-blurhash": "^1.1.2",
"focus-trap": "^7.5.2",
@ -57,6 +62,7 @@
"katex": "0.16.8",
"matter-js": "0.18.0",
"mfm-js": "0.23.3",
"paralint": "^1.2.1",
"photoswipe": "5.3.8",
"prettier": "3.0.0",
"prettier-plugin-vue": "1.1.6",

View File

@ -80,11 +80,11 @@ const emit = defineEmits<{
(ev: "resolved", reportId: string): void;
}>();
let forward = $ref(props.report.forwarded);
const forward = $ref(props.report.forwarded);
function resolve() {
os.apiWithDialog("admin/resolve-abuse-user-report", {
forward: forward,
forward,
reportId: props.report.id,
}).then(() => {
emit("resolved", props.report.id);

View File

@ -41,7 +41,7 @@
<script setup lang="ts">
import { ref } from "vue";
import * as Misskey from "calckey-js";
import type * as Misskey from "calckey-js";
import XWindow from "@/components/MkWindow.vue";
import MkTextarea from "@/components/form/textarea.vue";
import MkButton from "@/components/MkButton.vue";

View File

@ -109,12 +109,12 @@
<script lang="ts" setup>
import {
ref,
computed,
onMounted,
onBeforeUnmount,
shallowRef,
nextTick,
onBeforeUnmount,
onMounted,
ref,
shallowRef,
} from "vue";
import tinycolor from "tinycolor2";
import { globalEvents } from "@/events.js";
@ -173,21 +173,21 @@ const texts = computed(() => {
return angles;
});
let enabled = true;
let majorGraduationColor = $ref<string>();
let enabled = true,
majorGraduationColor = $ref<string>(),
// let minorGraduationColor = $ref<string>();
let sHandColor = $ref<string>();
let mHandColor = $ref<string>();
let hHandColor = $ref<string>();
let nowColor = $ref<string>();
let h = $ref<number>(0);
let m = $ref<number>(0);
let s = $ref<number>(0);
let hAngle = $ref<number>(0);
let mAngle = $ref<number>(0);
let sAngle = $ref<number>(0);
let disableSAnimate = $ref(false);
let sOneRound = false;
sHandColor = $ref<string>(),
mHandColor = $ref<string>(),
hHandColor = $ref<string>(),
nowColor = $ref<string>(),
h = $ref<number>(0),
m = $ref<number>(0),
s = $ref<number>(0),
hAngle = $ref<number>(0),
mAngle = $ref<number>(0),
sAngle = $ref<number>(0),
disableSAnimate = $ref(false),
sOneRound = false;
function tick() {
const now = new Date();

View File

@ -85,11 +85,11 @@
<script lang="ts">
import {
markRaw,
ref,
onUpdated,
onMounted,
onBeforeUnmount,
nextTick,
onBeforeUnmount,
onMounted,
onUpdated,
ref,
watch,
} from "vue";
import contains from "@/scripts/contains";
@ -99,17 +99,17 @@ import { acct } from "@/filters/user";
import * as os from "@/os";
import { MFM_TAGS } from "@/scripts/mfm-tags";
import { defaultStore } from "@/store";
import { emojilist, addSkinTone } from "@/scripts/emojilist";
import { addSkinTone, emojilist } from "@/scripts/emojilist";
import { instance } from "@/instance";
import { i18n } from "@/i18n";
type EmojiDef = {
interface EmojiDef {
emoji: string;
name: string;
aliasOf?: string;
url?: string;
isCustomEmoji?: boolean;
};
}
const lib = emojilist.filter((x) => x.category !== "flags");

View File

@ -49,8 +49,8 @@ const emit = defineEmits<{
(ev: "click", payload: MouseEvent): void;
}>();
let el = $ref<HTMLElement | null>(null);
let ripples = $ref<HTMLElement | null>(null);
const el = $ref<HTMLElement | null>(null);
const ripples = $ref<HTMLElement | null>(null);
onMounted(() => {
if (props.autofocus) {

View File

@ -6,11 +6,11 @@
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { defaultStore } from "@/store";
import { i18n } from "@/i18n";
type Captcha = {
interface Captcha {
render(
container: string | Node,
options: {
@ -31,7 +31,7 @@ type Captcha = {
execute(id: string): void;
reset(id?: string): void;
getResponse(id: string): string;
};
}
type CaptchaProvider = "hcaptcha" | "recaptcha";
@ -105,7 +105,7 @@ function requestRender() {
captcha.value.render(captchaEl.value, {
sitekey: props.sitekey,
theme: defaultStore.state.darkMode ? "dark" : "light",
callback: callback,
callback,
"expired-callback": callback,
"error-callback": callback,
});

View File

@ -24,7 +24,8 @@
<script lang="ts" setup>
import MkChannelPreview from "@/components/MkChannelPreview.vue";
import MkPagination, { Paging } from "@/components/MkPagination.vue";
import type { Paging } from "@/components/MkPagination.vue";
import MkPagination from "@/components/MkPagination.vue";
import { i18n } from "@/i18n";
const props = withDefaults(

View File

@ -8,23 +8,24 @@
</template>
<script lang="ts" setup>
import { onMounted, ref, watch, PropType, onUnmounted } from "vue";
import type { PropType } from "vue";
import { onMounted, onUnmounted, ref, watch } from "vue";
import {
Chart,
ArcElement,
LineElement,
BarElement,
PointElement,
BarController,
LineController,
BarElement,
CategoryScale,
LinearScale,
TimeScale,
Chart,
Filler,
Legend,
LineController,
LineElement,
LinearScale,
PointElement,
SubTitle,
TimeScale,
Title,
Tooltip,
SubTitle,
Filler,
} from "chart.js";
import "chartjs-adapter-date-fns";
import { enUS } from "date-fns/locale";
@ -127,8 +128,8 @@ const getColor = (i) => {
};
const now = new Date();
let chartInstance: Chart = null;
let chartData: {
let chartInstance: Chart = null,
chartData: {
series: {
name: string;
type: "line" | "area";

View File

@ -26,7 +26,7 @@
: message.user
"
:show-indicator="true"
disableLink
disable-link
/>
<header v-if="message.groupId">
<span class="name">{{ message.group.name }}</span>

View File

@ -12,9 +12,9 @@
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from "vue";
import { onBeforeUnmount, onMounted } from "vue";
import MkMenu from "./MkMenu.vue";
import { MenuItem } from "./types/menu.vue";
import type { MenuItem } from "./types/menu.vue";
import contains from "@/scripts/contains";
import * as os from "@/os";
@ -27,13 +27,13 @@ const emit = defineEmits<{
(ev: "closed"): void;
}>();
let rootEl = $ref<HTMLDivElement>();
const rootEl = $ref<HTMLDivElement>();
let zIndex = $ref<number>(os.claimZIndex("high"));
const zIndex = $ref<number>(os.claimZIndex("high"));
onMounted(() => {
let left = props.ev.pageX + 1; // + 1
let top = props.ev.pageY + 1; // + 1
let left = props.ev.pageX + 1, // + 1
top = props.ev.pageY + 1; // + 1
const width = rootEl.offsetWidth;
const height = rootEl.offsetHeight;

View File

@ -37,7 +37,7 @@
<script lang="ts" setup>
import { nextTick, onMounted } from "vue";
import * as misskey from "calckey-js";
import type * as misskey from "calckey-js";
import Cropper from "cropperjs";
import tinycolor from "tinycolor2";
import XModalWindow from "@/components/MkModalWindow.vue";
@ -62,10 +62,10 @@ const props = defineProps<{
const imgUrl = `${url}/proxy/image.webp?${query({
url: props.file.url,
})}`;
let dialogEl = $ref<InstanceType<typeof XModalWindow>>();
let imgEl = $ref<HTMLImageElement>();
let cropper: Cropper | null = null;
let loading = $ref(true);
const dialogEl = $ref<InstanceType<typeof XModalWindow>>();
const imgEl = $ref<HTMLImageElement>();
let cropper: Cropper | null = null,
loading = $ref(true);
const ok = async () => {
const promise = new Promise<misskey.entities.DriveFile>(async (res) => {

View File

@ -15,7 +15,7 @@
<script lang="ts" setup>
import { computed, ref } from "vue";
import { length } from "stringz";
import * as misskey from "calckey-js";
import type * as misskey from "calckey-js";
import { concat } from "@/scripts/array";
import { i18n } from "@/i18n";

View File

@ -1,5 +1,6 @@
<script lang="ts">
import { defineComponent, h, PropType, TransitionGroup } from "vue";
import type { PropType } from "vue";
import { TransitionGroup, defineComponent, h } from "vue";
import MkAd from "@/components/global/MkAd.vue";
import { i18n } from "@/i18n";
import { defaultStore } from "@/store";
@ -51,7 +52,7 @@ export default defineComponent({
if (!slots || !slots.default) return;
const el = slots.default({
item: item,
item,
})[0];
if (el.key == null && item.id) el.key = item.id;

View File

@ -57,17 +57,17 @@
<Mfm :text="text" />
</div>
<MkInput
ref="inputEl"
v-if="input && input.type !== 'paragraph'"
ref="inputEl"
v-model="inputValue"
autofocus
:autocomplete="input.autocomplete"
:type="input.type == 'search' ? 'search' : input.type || 'text'"
:placeholder="input.placeholder || undefined"
@keydown="onInputKeydown"
:style="{
width: input.type === 'search' ? '300px' : null,
}"
@keydown="onInputKeydown"
>
<template v-if="input.type === 'password'" #prefix
><i class="ph-password ph-bold ph-lg"></i
@ -100,9 +100,9 @@
</template>
<template v-if="input.type === 'search'" #suffix>
<button
v-tooltip.noDelay="i18n.ts.filter"
class="_buttonIcon"
@click.stop="openSearchFilters"
v-tooltip.noDelay="i18n.ts.filter"
>
<i class="ph-funnel ph-bold"></i>
</button>
@ -200,6 +200,7 @@
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref, shallowRef } from "vue";
import * as Acct from "calckey-js/built/acct";
import MkModal from "@/components/MkModal.vue";
import MkButton from "@/components/MkButton.vue";
import MkInput from "@/components/form/input.vue";
@ -207,18 +208,17 @@ import MkTextarea from "@/components/form/textarea.vue";
import MkSelect from "@/components/form/select.vue";
import * as os from "@/os";
import { i18n } from "@/i18n";
import * as Acct from "calckey-js/built/acct";
type Input = {
interface Input {
type: HTMLInputElement["type"];
placeholder?: string | null;
autocomplete?: string;
default: string | number | null;
minLength?: number;
maxLength?: number;
};
}
type Select = {
interface Select {
items: {
value: string;
text: string;
@ -231,7 +231,7 @@ type Select = {
}[];
}[];
default: string | null;
};
}
const props = withDefaults(
defineProps<{

View File

@ -49,8 +49,8 @@
<button
class="_button"
:class="$style.close"
@click="close"
:aria-label="i18n.t('close')"
@click="close"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
@ -59,14 +59,14 @@
</template>
<script lang="ts" setup>
import { ref, nextTick } from "vue";
import { nextTick, ref } 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 show = ref(false);
const emit = defineEmits<{
(ev: "closed"): void;

View File

@ -195,7 +195,7 @@ const props = withDefaults(
);
const emit = defineEmits<{
(ev: "chosen", v: string): void;
(ev: "chosen", v: string, ev: MouseEvent): void;
}>();
const search = ref<HTMLInputElement>();
@ -436,7 +436,7 @@ function chosen(emoji: any, ev?: MouseEvent) {
}
const key = getKey(emoji);
emit("chosen", key);
emit("chosen", key, ev);
// 使
if (!pinned.value.includes(key)) {

View File

@ -58,29 +58,15 @@ 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) {
if (ev?.shiftKey) return;
modal.value?.close(ev);
}
}
function chosen(emoji: any) {
function chosen(emoji: any, ev: MouseEvent) {
emit("done", emoji);
checkForShift();
checkForShift(ev);
}
function opening() {
@ -91,16 +77,6 @@ function opening() {
}
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>

View File

@ -54,7 +54,7 @@
controls
@contextmenu.stop
>
<source :src="media.url" :type="media.type" />
<source :src="media.url" :type="mediaType" />
</video>
</VuePlyr>
</template>
@ -80,7 +80,7 @@
</template>
<script lang="ts" setup>
import { watch, ref } from "vue";
import { watch, ref, computed } from "vue";
import VuePlyr from "vue-plyr";
import "vue-plyr/dist/vue-plyr.css";
import type * as misskey from "calckey-js";
@ -107,6 +107,12 @@ const url =
? getStaticImageUrl(props.media.thumbnailUrl)
: props.media.thumbnailUrl;
const mediaType = computed(() => {
return props.media.type === "video/quicktime"
? "video/mp4"
: props.media.type;
});
function captionPopup() {
os.alert({
type: "info",

View File

@ -148,7 +148,7 @@
{{ appearNote.channel.name }}</MkA
>
</div>
<footer ref="footerEl" class="footer" @click.stop tabindex="-1">
<footer ref="footerEl" class="footer" tabindex="-1">
<XReactionsViewer
v-if="enableEmojiReactions"
ref="reactionsViewer"
@ -157,7 +157,7 @@
<button
v-tooltip.noDelay.bottom="i18n.ts.reply"
class="button _button"
@click="reply()"
@click.stop="reply()"
>
<i class="ph-arrow-u-up-left ph-bold ph-lg"></i>
<template
@ -202,7 +202,7 @@
ref="reactButton"
v-tooltip.noDelay.bottom="i18n.ts.reaction"
class="button _button"
@click="react()"
@click.stop="react()"
>
<i class="ph-smiley ph-bold ph-lg"></i>
</button>
@ -213,7 +213,7 @@
"
ref="reactButton"
class="button _button reacted"
@click="undoReact(appearNote)"
@click.stop="undoReact(appearNote)"
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
>
<i class="ph-minus ph-bold ph-lg"></i>
@ -223,7 +223,7 @@
ref="menuButton"
v-tooltip.noDelay.bottom="i18n.ts.more"
class="button _button"
@click="menu()"
@click.stop="menu()"
>
<i class="ph-dots-three-outline ph-bold ph-lg"></i>
</button>
@ -862,7 +862,6 @@ defineExpose({
z-index: 2;
display: flex;
flex-wrap: wrap;
pointer-events: none; // Allow clicking anything w/out pointer-events: all; to open post
margin-top: 0.4em;
> :deep(.button) {
position: relative;
@ -876,7 +875,6 @@ defineExpose({
max-width: 3.5em;
width: max-content;
min-width: max-content;
pointer-events: all;
height: auto;
transition: opacity 0.2s;
&::before {

View File

@ -33,11 +33,7 @@
detailedView
></MkNote>
<MkTab
v-model="tab"
:style="'underline'"
@update:modelValue="loadTab"
>
<MkTab v-model="tab" :style="'underline'" @update:modelValue="loadTab">
<option value="replies">
<!-- <i class="ph-arrow-u-up-left ph-bold ph-lg"></i> -->
<span v-if="note.repliesCount > 0" class="count">{{

View File

@ -56,7 +56,7 @@
</div>
</div>
</div>
<footer ref="footerEl" class="footer" @click.stop tabindex="-1">
<footer ref="footerEl" class="footer" tabindex="-1">
<XReactionsViewer
v-if="enableEmojiReactions"
ref="reactionsViewer"
@ -65,7 +65,7 @@
<button
v-tooltip.noDelay.bottom="i18n.ts.reply"
class="button _button"
@click="reply()"
@click.stop="reply()"
>
<i class="ph-arrow-u-up-left ph-bold ph-lg"></i>
<template v-if="appearNote.repliesCount > 0">
@ -107,7 +107,7 @@
ref="reactButton"
v-tooltip.noDelay.bottom="i18n.ts.reaction"
class="button _button"
@click="react()"
@click.stop="react()"
>
<i class="ph-smiley ph-bold ph-lg"></i>
</button>
@ -118,7 +118,7 @@
"
ref="reactButton"
class="button _button reacted"
@click="undoReact(appearNote)"
@click.stop="undoReact(appearNote)"
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
>
<i class="ph-minus ph-bold ph-lg"></i>
@ -128,7 +128,7 @@
ref="menuButton"
v-tooltip.noDelay.bottom="i18n.ts.more"
class="button _button"
@click="menu()"
@click.stop="menu()"
>
<i class="ph-dots-three-outline ph-bold ph-lg"></i>
</button>
@ -470,7 +470,6 @@ function noteClick(e) {
z-index: 2;
display: flex;
flex-wrap: wrap;
pointer-events: none; // Allow clicking anything w/out pointer-events: all; to open post
> :deep(.button) {
position: relative;
@ -484,7 +483,6 @@ function noteClick(e) {
max-width: 3.5em;
width: max-content;
min-width: max-content;
pointer-events: all;
height: auto;
transition: opacity 0.2s;
&::before {

View File

@ -3,7 +3,7 @@
v-if="canRenote && $store.state.seperateRenoteQuote"
v-tooltip.noDelay.bottom="i18n.ts.quote"
class="eddddedb _button"
@click="quote()"
@click.stop="quote()"
>
<i class="ph-quotes ph-bold ph-lg"></i>
</button>

View File

@ -9,7 +9,7 @@
canToggle,
newlyAdded: !isInitial,
}"
@click="toggleReaction()"
@click.stop="toggleReaction()"
>
<XReactionIcon
class="icon"
@ -100,13 +100,20 @@ useTooltip(
<style lang="scss" scoped>
.hkzvhatu {
position: relative;
display: inline-block;
height: 32px;
margin: 2px;
padding: 0 6px;
border-radius: 4px;
margin-block: 2px;
padding: 0 8px;
pointer-events: all;
min-width: max-content;
&::before {
content: "";
position: absolute;
inset: 0 2px;
border-radius: 4px;
z-index: -1;
}
&.newlyAdded {
animation: scaleInSmall 0.3s cubic-bezier(0, 0, 0, 1.2);
:deep(.mk-emoji) {
@ -126,9 +133,10 @@ useTooltip(
}
}
&.canToggle {
&::before {
background: rgba(0, 0, 0, 0.05);
&:hover {
}
&:hover:not(.reacted)::before {
background: rgba(0, 0, 0, 0.1);
}
}
@ -139,9 +147,7 @@ useTooltip(
&.reacted {
order: -1;
background: var(--accent);
&:hover {
&::before {
background: var(--accent);
}

View File

@ -1,5 +1,9 @@
<template>
<div ref="reactionsEl" class="reactions-list tdflqwzn" :class="{ isMe }">
<div
ref="reactionsEl"
class="reactions-list swiper-no-swiping tdflqwzn"
:class="{ isMe }"
>
<XReaction
v-for="(count, reaction) in note.reactions"
:key="reaction"
@ -50,6 +54,11 @@ const isMe = computed(() => $i && $i.id === props.note.userId);
transparent
);
scrollbar-width: none;
pointer-events: none;
:deep(*) {
pointer-events: all;
}
&::-webkit-scrollbar {
display: none;
}

View File

@ -5,7 +5,7 @@
v-tooltip.noDelay.bottom="i18n.ts.renote"
class="button _button canRenote"
:class="{ renoted: hasRenotedBefore }"
@click="renote(false, $event)"
@click.stop="renote(false, $event)"
>
<i class="ph-repeat ph-bold ph-lg"></i>
<p v-if="count > 0 && !detailedView" class="count">{{ count }}</p>

View File

@ -2,7 +2,7 @@
<button
v-tooltip.noDelay.bottom="i18n.ts._gallery.like"
class="button _button"
@click="star($event)"
@click.stop="star($event)"
>
<svg
v-if="defaultStore.state.woozyMode === true"

View File

@ -4,7 +4,7 @@
class="button _button"
:class="$style.root"
ref="buttonRef"
@click="toggleStar($event)"
@click.stop="toggleStar($event)"
>
<span v-if="!reacted">
<i

View File

@ -47,13 +47,13 @@
<script lang="ts" setup>
import {
computed,
nextTick,
onMounted,
onUnmounted,
nextTick,
ref,
watch,
computed,
toRefs,
watch,
} from "vue";
import { debounce } from "throttle-debounce";
import MkButton from "@/components/MkButton.vue";

View File

@ -4,7 +4,7 @@
type="radio"
:disabled="disabled"
:checked="checked"
v-on:change="(x) => toggle(x)"
@change="(x) => toggle(x)"
/>
<span class="button">
<span></span>
@ -26,7 +26,7 @@ const emit = defineEmits<{
(ev: "update:modelValue", value: any): void;
}>();
let checked = $computed(() => props.modelValue === props.value);
const checked = $computed(() => props.modelValue === props.value);
function toggle(x) {
if (props.disabled) return;

View File

@ -12,7 +12,7 @@
:list="id"
:value="modelValue"
:disabled="disabled"
v-on:change="(x) => onChange(x)"
@change="(x) => onChange(x)"
@focus="tooltipShow"
@blur="tooltipHide"
@touchstart="tooltipShow"
@ -35,7 +35,7 @@
</template>
<script lang="ts" setup>
import { ref, computed, defineAsyncComponent } from "vue";
import { computed, defineAsyncComponent, ref } from "vue";
import * as os from "@/os";
const id = os.getUniqueId();
@ -59,7 +59,7 @@ const props = withDefaults(
);
const inputEl = ref<HTMLElement>();
let inputVal = $ref(props.modelValue);
const inputVal = $ref(props.modelValue);
const emit = defineEmits<{
(ev: "update:modelValue", value: number): void;

View File

@ -43,15 +43,15 @@
</template>
<script lang="ts" setup>
import type { VNode } from "vue";
import {
onMounted,
nextTick,
ref,
watch,
computed,
nextTick,
onMounted,
ref,
toRefs,
VNode,
useSlots,
watch,
} from "vue";
import MkButton from "@/components/MkButton.vue";
import * as os from "@/os";
@ -151,7 +151,7 @@ function show(ev: MouseEvent) {
opening.value = true;
const menu = [];
let options = slots.default!();
const options = slots.default!();
const pushOption = (option: VNode) => {
menu.push({

View File

@ -22,7 +22,8 @@
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watch } from "vue";
import type { PropType } from "vue";
import { defineComponent, ref, watch } from "vue";
import MkButton from "@/components/MkButton.vue";
import { i18n } from "@/i18n";

View File

@ -4,7 +4,7 @@
type="checkbox"
:checked="modelValue"
:disabled="disabled"
v-on:change="(x) => toggle(x)"
@change="(x) => toggle(x)"
/>
<div class="button">
<div class="knob"></div>
@ -18,7 +18,7 @@
</template>
<script lang="ts" setup>
import { Ref } from "vue";
import type { Ref } from "vue";
const props = defineProps<{
modelValue: boolean | Ref<boolean>;

View File

@ -39,14 +39,14 @@
<script lang="ts">
import {
computed,
defineComponent,
nextTick,
onMounted,
onUnmounted,
nextTick,
ref,
watch,
computed,
toRefs,
watch,
} from "vue";
import { debounce } from "throttle-debounce";
import MkButton from "@/components/MkButton.vue";

View File

@ -10,7 +10,7 @@
</template>
<script lang="ts" setup>
import * as misskey from "calckey-js";
import type * as misskey from "calckey-js";
import { toUnicode } from "punycode/";
import { host as hostRaw } from "@/config";

View File

@ -1,7 +1,7 @@
<template>
<div
v-if="chosen && chosen.length > 0 && defaultStore.state.showAds"
v-for="chosenItem in chosen"
v-if="chosen && chosen.length > 0 && defaultStore.state.showAds"
class="qiivuoyo"
>
<div v-if="!showMenu" class="main" :class="chosenItem.place">

View File

@ -37,7 +37,7 @@
<script lang="ts" setup>
import { onMounted, watch } from "vue";
import * as misskey from "calckey-js";
import type * as misskey from "calckey-js";
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
import { extractAvgColorFromBlurhash } from "@/scripts/extract-avg-color-from-blurhash";
import { acct, userPage } from "@/filters/user";

View File

@ -22,7 +22,7 @@
<script lang="ts" setup>
import { computed, ref, watch } from "vue";
import { CustomEmoji } from "calckey-js/built/entities";
import type { CustomEmoji } from "calckey-js/built/entities";
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
import { char2filePath } from "@/scripts/twemoji-base";
import { defaultStore } from "@/store";

View File

@ -4,8 +4,8 @@
:plain="plain"
:nowrap="nowrap"
:author="author"
:customEmojis="customEmojis"
:isNote="isNote"
:custom-emojis="customEmojis"
:is-note="isNote"
class="mfm-object"
:class="{
nowrap,

View File

@ -11,10 +11,10 @@
<div class="buttons">
<button
v-if="displayBackButton"
v-tooltip.noDelay="i18n.ts.goBack"
class="_buttonIcon button icon backButton"
@click.stop="goBack()"
@touchstart="preventDrag"
v-tooltip.noDelay="i18n.ts.goBack"
>
<i class="ph-caret-left ph-bold ph-lg"></i>
</button>
@ -23,7 +23,7 @@
class="avatar button"
:user="$i"
:disable-preview="true"
disableLink
disable-link
@click.stop="openAccountMenu"
/>
</div>
@ -68,8 +68,8 @@
</div>
<template v-if="metadata">
<nav
ref="tabsEl"
v-if="hasTabs"
ref="tabsEl"
class="tabs"
:class="{ collapse: hasTabs && tabs.length > 3 }"
>
@ -123,14 +123,14 @@
<script lang="ts" setup>
import {
computed,
inject,
nextTick,
onMounted,
onUnmounted,
ref,
inject,
watch,
shallowReactive,
nextTick,
reactive,
ref,
shallowReactive,
watch,
} from "vue";
import MkFollowButton from "@/components/MkFollowButton.vue";
import { popupMenu } from "@/os";
@ -140,13 +140,13 @@ import { injectPageMetadata } from "@/scripts/page-metadata";
import { $i, openAccountMenu as openAccountMenu_ } from "@/account";
import { i18n } from "@/i18n";
type Tab = {
interface Tab {
key?: string | null;
title: string;
icon?: string;
iconOnly?: boolean;
onClick?: (ev: MouseEvent) => void;
};
}
const props = defineProps<{
tabs?: Tab[];

View File

@ -24,10 +24,10 @@ const props = withDefaults(
},
);
let ro: ResizeObserver;
let root = $ref<HTMLElement>();
let content = $ref<HTMLElement>();
let margin = $ref(0);
let ro: ResizeObserver,
root = $ref<HTMLElement>(),
content = $ref<HTMLElement>(),
margin = $ref(0);
const shouldSpacerMin = inject("shouldSpacerMin", false);
const adjust = (rect: { width: number; height: number }) => {

View File

@ -16,14 +16,15 @@ const CURRENT_STICKY_TOP = "CURRENT_STICKY_TOP";
</script>
<script lang="ts" setup>
import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from "vue";
import type { Ref } from "vue";
import { inject, onMounted, onUnmounted, provide, ref, watch } from "vue";
const rootEl = $ref<HTMLElement>();
const headerEl = $ref<HTMLElement>();
const bodyEl = $ref<HTMLElement>();
let headerHeight = $ref<string | undefined>();
let childStickyTop = $ref(0);
let headerHeight = $ref<string | undefined>(),
childStickyTop = $ref(0);
const parentStickyTop = inject<Ref<number>>(CURRENT_STICKY_TOP, ref(0));
provide(CURRENT_STICKY_TOP, $$(childStickyTop));

View File

@ -10,7 +10,7 @@
<script lang="ts" setup>
import {} from "vue";
import * as misskey from "calckey-js";
import type * as misskey from "calckey-js";
const props = withDefaults(
defineProps<{

View File

@ -5,8 +5,8 @@
:is="currentPageComponent"
:key="key"
v-bind="Object.fromEntries(currentPageProps)"
tabindex="-1"
v-focus
tabindex="-1"
style="outline: none"
/>
@ -27,7 +27,7 @@ import {
provide,
watch,
} from "vue";
import { Resolved, Router } from "@/nirax";
import type { Resolved, Router } from "@/nirax";
import { defaultStore } from "@/store";
const props = defineProps<{
@ -56,9 +56,9 @@ function resolveNested(current: Resolved, d = 0): Resolved | null {
}
const current = resolveNested(router.current)!;
let currentPageComponent = $shallowRef(current.route.component);
let currentPageProps = $ref(current.props);
let key = $ref(
let currentPageComponent = $shallowRef(current.route.component),
currentPageProps = $ref(current.props),
key = $ref(
current.route.path + JSON.stringify(Object.fromEntries(current.props)),
);

View File

@ -222,7 +222,7 @@ const importPosts = async (ev) => {
const file = await selectFile(ev.currentTarget ?? ev.target);
os.api("i/import-posts", {
fileId: file.id,
signatureCheck: importType.value === "mastodon" ? true : false,
signatureCheck: false,
})
.then(onImportSuccess)
.catch(onError);

View File

@ -260,6 +260,15 @@ export function getUserMenu(user, router: Router = mainRouter) {
to: `/my/messaging/${Acct.toString(user)}`,
}
: undefined,
user.host != null && user.url
? {
type: "a",
icon: "ph-arrow-square-out ph-bold ph-lg",
text: i18n.ts.showOnRemote,
href: user.url,
target: "_blank",
}
: undefined,
null,
{
icon: "ph-list-bullets ph-bold ph-lg",

View File

@ -193,12 +193,12 @@ import {
import { v4 as uuid } from "uuid";
import XCommon from "./_common_/common.vue";
import {
deckStore,
addColumn as addColumnToStore,
loadDeck,
getProfiles,
renameProfile as renameProfile_,
deckStore,
deleteProfile as deleteProfile_,
getProfiles,
loadDeck,
renameProfile as renameProfile_,
} from "./deck/deck-store";
import DeckColumnCore from "@/ui/deck/column-core.vue";
import XSidebar from "@/ui/_common_/navbar.vue";
@ -253,7 +253,7 @@ function showSettings() {
os.pageWindow("/settings/deck");
}
let columnsEl = $ref<HTMLElement>();
const columnsEl = $ref<HTMLElement>();
const addColumn = async (ev) => {
const columns = [

View File

@ -23,7 +23,8 @@
<script lang="ts" setup>
import { onMounted } from "vue";
import XColumn from "./column.vue";
import { updateColumn, Column } from "./deck-store";
import type { Column } from "./deck-store";
import { updateColumn } from "./deck-store";
import XTimeline from "@/components/MkTimeline.vue";
import * as os from "@/os";
import { i18n } from "@/i18n";
@ -38,7 +39,7 @@ const emit = defineEmits<{
(ev: "parent-focus", direction: "up" | "down" | "left" | "right"): void;
}>();
let timeline = $ref<InstanceType<typeof XTimeline>>();
const timeline = $ref<InstanceType<typeof XTimeline>>();
onMounted(() => {
if (props.column.antennaId == null) {

View File

@ -23,7 +23,8 @@
<script lang="ts" setup>
import {} from "vue";
import XColumn from "./column.vue";
import { updateColumn, Column } from "./deck-store";
import type { Column } from "./deck-store";
import { updateColumn } from "./deck-store";
import XTimeline from "@/components/MkTimeline.vue";
import * as os from "@/os";
import { i18n } from "@/i18n";
@ -38,7 +39,7 @@ const emit = defineEmits<{
(ev: "parent-focus", direction: "up" | "down" | "left" | "right"): void;
}>();
let timeline = $ref<InstanceType<typeof XTimeline>>();
const timeline = $ref<InstanceType<typeof XTimeline>>();
if (props.column.channelId == null) {
setChannel();

View File

@ -68,7 +68,7 @@ import XWidgetsColumn from "./widgets-column.vue";
import XMentionsColumn from "./mentions-column.vue";
import XDirectColumn from "./direct-column.vue";
import XChannelColumn from "./channel-column.vue";
import { Column } from "./deck-store";
import type { Column } from "./deck-store";
defineProps<{
column?: Column;

View File

@ -56,23 +56,23 @@
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, provide, Ref, watch } from "vue";
import { Ref, onBeforeUnmount, onMounted, provide, watch } from "vue";
import type { Column } from "./deck-store";
import {
updateColumn,
deckStore,
popRightColumn,
removeColumn,
stackLeftColumn,
swapColumn,
swapDownColumn,
swapLeftColumn,
swapRightColumn,
swapUpColumn,
swapDownColumn,
stackLeftColumn,
popRightColumn,
removeColumn,
swapColumn,
Column,
deckStore,
updateColumn,
} from "./deck-store";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { MenuItem } from "@/types/menu";
import type { MenuItem } from "@/types/menu";
provide("shouldHeaderThin", true);
provide("shouldOmitHeaderTitle", true);
@ -99,15 +99,15 @@ const emit = defineEmits<{
(ev: "headerWheel", ctx: WheelEvent): void;
}>();
let body = $ref<HTMLDivElement>();
const body = $ref<HTMLDivElement>();
let dragging = $ref(false);
watch($$(dragging), (v) =>
os.deckGlobalEvents.emit(v ? "column.dragStart" : "column.dragEnd"),
);
let draghover = $ref(false);
let dropready = $ref(false);
let draghover = $ref(false),
dropready = $ref(false);
const isMainColumn = $computed(() => props.column.type === "main");
const active = $computed(() => props.column.active !== false);

View File

@ -20,6 +20,7 @@ export type Column = {
| "notifications"
| "tl"
| "antenna"
| "channel"
| "list"
| "mentions"
| "direct";
@ -29,9 +30,10 @@ export type Column = {
active?: boolean;
flexible?: boolean;
antennaId?: string;
channelId?: string;
listId?: string;
includingTypes?: typeof notificationTypes[number][];
tl?: "home" | "local" | "social" | "global";
tl?: "home" | "local" | "social" | "recommended" | "global";
};
export const deckStore = markRaw(

View File

@ -19,8 +19,8 @@
<script lang="ts" setup>
import {} from "vue";
import XColumn from "./column.vue";
import type { Column } from "./deck-store";
import XNotes from "@/components/MkNotes.vue";
import { Column } from "./deck-store";
defineProps<{
column: Column;

View File

@ -23,7 +23,8 @@
<script lang="ts" setup>
import {} from "vue";
import XColumn from "./column.vue";
import { updateColumn, Column } from "./deck-store";
import type { Column } from "./deck-store";
import { updateColumn } from "./deck-store";
import XTimeline from "@/components/MkTimeline.vue";
import * as os from "@/os";
import { i18n } from "@/i18n";
@ -38,7 +39,7 @@ const emit = defineEmits<{
(ev: "parent-focus", direction: "up" | "down" | "left" | "right"): void;
}>();
let timeline = $ref<InstanceType<typeof XTimeline>>();
const timeline = $ref<InstanceType<typeof XTimeline>>();
if (props.column.listId == null) {
setList();

View File

@ -20,14 +20,16 @@
</template>
<script lang="ts" setup>
import { ComputedRef, provide } from "vue";
import type { ComputedRef } from "vue";
import { provide } from "vue";
import XColumn from "./column.vue";
import { deckStore, Column } from "@/ui/deck/deck-store";
import type { Column } from "@/ui/deck/deck-store";
import { deckStore } from "@/ui/deck/deck-store";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { mainRouter } from "@/router";
import type { PageMetadata } from "@/scripts/page-metadata";
import {
PageMetadata,
provideMetadataReceiver,
setPageMetadata,
} from "@/scripts/page-metadata";
@ -67,7 +69,7 @@ function onContextmenu(ev: MouseEvent) {
["INPUT", "TEXTAREA", "IMG", "VIDEO", "CANVAS"].includes(
(ev.target as HTMLElement).tagName,
) ||
(ev.target as HTMLElement).attributes["contenteditable"]
(ev.target as HTMLElement).attributes.contenteditable
)
return;
if (window.getSelection()?.toString() !== "") return;

View File

@ -16,8 +16,8 @@
<script lang="ts" setup>
import {} from "vue";
import XColumn from "./column.vue";
import type { Column } from "./deck-store";
import XNotes from "@/components/MkNotes.vue";
import { Column } from "./deck-store";
defineProps<{
column: Column;

View File

@ -44,7 +44,7 @@ function func(): void {
done: async (res) => {
const { includingTypes } = res;
updateColumn(props.column.id, {
includingTypes: includingTypes,
includingTypes,
});
},
},

View File

@ -46,7 +46,8 @@
<script lang="ts" setup>
import { onMounted } from "vue";
import XColumn from "./column.vue";
import { removeColumn, updateColumn, Column } from "./deck-store";
import type { Column } from "./deck-store";
import { removeColumn, updateColumn } from "./deck-store";
import XTimeline from "@/components/MkTimeline.vue";
import * as os from "@/os";
import { $i } from "@/account";
@ -63,9 +64,9 @@ const emit = defineEmits<{
(ev: "parent-focus", direction: "up" | "down" | "left" | "right"): void;
}>();
let disabled = $ref(false);
let indicated = $ref(false);
let columnActive = $ref(true);
let disabled = $ref(false),
indicated = $ref(false),
columnActive = $ref(true);
onMounted(() => {
if (props.column.tl == null) {

View File

@ -34,9 +34,9 @@
<script lang="ts" setup>
import {} from "vue";
import XColumn from "./column.vue";
import type { Column } from "./deck-store";
import {
addColumnWidget,
Column,
removeColumnWidget,
setColumnWidgets,
updateColumnWidget,

View File

@ -169,10 +169,10 @@
</template>
<script lang="ts" setup>
import { defineAsyncComponent, provide, onMounted, computed, ref } from "vue";
import XCommon from "./_common_/common.vue";
import { computed, defineAsyncComponent, onMounted, provide, ref } from "vue";
import * as Acct from "calckey-js/built/acct";
import type { ComputedRef } from "vue";
import XCommon from "./_common_/common.vue";
import type { PageMetadata } from "@/scripts/page-metadata";
import { instanceName, ui } from "@/config";
import XDrawerMenu from "@/ui/_common_/navbar-for-mobile.vue";
@ -232,7 +232,7 @@ const menuIndicated = computed(() => {
});
function updateButtonState(): void {
let routerState = window.location.pathname;
const routerState = window.location.pathname;
if (routerState === "/") {
buttonAnimIndex.value = 0;
return;
@ -246,7 +246,6 @@ function updateButtonState(): void {
return;
}
buttonAnimIndex.value = 3;
return;
}
updateButtonState();
@ -358,7 +357,7 @@ const onContextmenu = (ev: MouseEvent) => {
["INPUT", "TEXTAREA", "IMG", "VIDEO", "CANVAS"].includes(
ev.target.tagName,
) ||
ev.target.attributes["contenteditable"]
ev.target.attributes.contenteditable
)
return;
if (window.getSelection()?.toString() !== "") return;

View File

@ -39,8 +39,8 @@ const emit = defineEmits<{
(ev: "mounted", el: Element): void;
}>();
let editMode = $ref(false);
let rootEl = $ref<HTMLDivElement>();
const editMode = $ref(false);
const rootEl = $ref<HTMLDivElement>();
onMounted(() => {
emit("mounted", rootEl);

View File

@ -4,7 +4,7 @@
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
import { defineAsyncComponent, defineComponent } from "vue";
import DesignA from "./visitor/a.vue";
import DesignB from "./visitor/b.vue";
import XCommon from "./_common_/common.vue";

View File

@ -74,7 +74,7 @@
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
import { defineAsyncComponent, defineComponent } from "vue";
import XHeader from "./header.vue";
import { host, instanceName } from "@/config";
import { search } from "@/scripts/search";

View File

@ -71,7 +71,8 @@
</template>
<script lang="ts" setup>
import { ComputedRef, onMounted, provide } from "vue";
import type { ComputedRef } from "vue";
import { onMounted, provide } from "vue";
import XHeader from "./header.vue";
import XKanban from "./kanban.vue";
import { host, instanceName } from "@/config";
@ -84,8 +85,8 @@ import XSignupDialog from "@/components/MkSignupDialog.vue";
import MkButton from "@/components/MkButton.vue";
import { ColdDeviceStorage, defaultStore } from "@/store";
import { mainRouter } from "@/router";
import type { PageMetadata } from "@/scripts/page-metadata";
import {
PageMetadata,
provideMetadataReceiver,
setPageMetadata,
} from "@/scripts/page-metadata";
@ -111,10 +112,10 @@ const isTimelineAvailable =
!instance.disableLocalTimeline ||
!instance.disableRecommendedTimeline ||
!instance.disableGlobalTimeline;
let showMenu = $ref(false);
let isDesktop = $ref(window.innerWidth >= DESKTOP_THRESHOLD);
let narrow = $ref(window.innerWidth < 1280);
let meta = $ref();
const showMenu = $ref(false);
let isDesktop = $ref(window.innerWidth >= DESKTOP_THRESHOLD),
narrow = $ref(window.innerWidth < 1280),
meta = $ref();
const keymap = $computed(() => {
return {

View File

@ -81,7 +81,7 @@
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent } from "vue";
import { defineAsyncComponent, defineComponent } from "vue";
import { host, instanceName } from "@/config";
import * as os from "@/os";
import MkPagination from "@/components/MkPagination.vue";

View File

@ -7,11 +7,12 @@
</template>
<script lang="ts" setup>
import { provide, ComputedRef } from "vue";
import type { ComputedRef } from "vue";
import { provide } from "vue";
import XCommon from "./_common_/common.vue";
import { mainRouter } from "@/router";
import type { PageMetadata } from "@/scripts/page-metadata";
import {
PageMetadata,
provideMetadataReceiver,
setPageMetadata,
} from "@/scripts/page-metadata";

View File

@ -36,14 +36,14 @@ const props = defineProps<{
activity: any[];
}>();
let viewBoxX: number = $ref(147);
let viewBoxY: number = $ref(60);
let zoom: number = $ref(1);
let pos: number = $ref(0);
let pointsNote: any = $ref(null);
let pointsReply: any = $ref(null);
let pointsRenote: any = $ref(null);
let pointsTotal: any = $ref(null);
const viewBoxX: number = $ref(147);
const viewBoxY: number = $ref(60);
let zoom: number = $ref(1),
pos: number = $ref(0),
pointsNote: any = $ref(null),
pointsReply: any = $ref(null),
pointsRenote: any = $ref(null),
pointsTotal: any = $ref(null);
function dragListen(fn) {
window.addEventListener("mousemove", fn);
@ -65,8 +65,8 @@ function onMousedown(ev) {
//
dragListen((me) => {
let moveLeft = me.clientX - clickX;
let moveTop = me.clientY - clickY;
const moveLeft = me.clientX - clickX;
const moveTop = me.clientY - clickY;
zoom = Math.max(1, baseZoom + -moveTop / 20);
pos = Math.min(0, basePos + moveLeft);

View File

@ -38,17 +38,16 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref, watch } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import XCalendar from "./activity.calendar.vue";
import XChart from "./activity.chart.vue";
import MkHeatmap from "@/components/MkHeatmap.vue";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import MkContainer from "@/components/MkContainer.vue";
import { $i } from "@/account";

View File

@ -28,14 +28,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from "vue";
import { AiScript, parse, utils } from "@syuilo/aiscript";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import MkContainer from "@/components/MkContainer.vue";
import { createAiScriptEnv } from "@/scripts/aiscript/api";

View File

@ -9,14 +9,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from "vue";
import { AiScript, parse, utils } from "@syuilo/aiscript";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import { createAiScriptEnv } from "@/scripts/aiscript/api";
import { $i } from "@/account";

View File

@ -45,14 +45,13 @@
<script lang="ts" setup>
import { onUnmounted, ref } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import { i18n } from "@/i18n";
import { useInterval } from "@/scripts/use-interval";
import { $i } from "@/account";

View File

@ -47,14 +47,13 @@
<script lang="ts" setup>
import {} from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import MkContainer from "@/components/MkContainer.vue";
import MkAnalogClock from "@/components/MkAnalogClock.vue";
import MkDigitalClock from "@/components/MkDigitalClock.vue";

View File

@ -16,14 +16,13 @@
<script lang="ts" setup>
import { onUnmounted, ref, watch } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import { timezones } from "@/scripts/timezones";
import MkDigitalClock from "@/components/MkDigitalClock.vue";

View File

@ -49,14 +49,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import MkContainer from "@/components/MkContainer.vue";
import MkMiniChart from "@/components/MkMiniChart.vue";
import * as os from "@/os";

View File

@ -22,9 +22,9 @@
<script lang="ts" setup>
import {} from "vue";
import {
useWidgetPropsManager,
WidgetComponentEmits,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import type { Widget, WidgetComponentExpose } from "./widget";
import type { GetFormResultType } from "@/scripts/form";
@ -58,7 +58,7 @@ const { widgetProps, configure } = useWidgetPropsManager(
emit,
);
let cloud = $ref<InstanceType<typeof MkTagCloud> | null>();
const cloud = $ref<InstanceType<typeof MkTagCloud> | null>();
let activeInstances = $shallowRef(null);
function onInstanceClick(i) {

View File

@ -124,14 +124,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import { stream } from "@/stream";
import number from "@/filters/number";
import * as sound from "@/scripts/sound";

View File

@ -24,14 +24,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref, watch } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import MkContainer from "@/components/MkContainer.vue";
import { defaultStore } from "@/store";

View File

@ -31,14 +31,13 @@
<script lang="ts" setup>
import { defineAsyncComponent } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import MkContainer from "@/components/MkContainer.vue";
import XNotifications from "@/components/MkNotifications.vue";
import * as os from "@/os";

View File

@ -21,14 +21,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import { useInterval } from "@/scripts/use-interval";
import { i18n } from "@/i18n";

View File

@ -27,14 +27,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import { stream } from "@/stream";
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
import * as os from "@/os";

View File

@ -9,14 +9,13 @@
<script lang="ts" setup>
import {} from "vue";
import { GetFormResultType } from "@/scripts/form";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import type { GetFormResultType } from "@/scripts/form";
import XPostForm from "@/components/MkPostForm.vue";
const name = "postForm";

View File

@ -38,15 +38,14 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import MarqueeText from "@/components/MkMarquee.vue";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import MkContainer from "@/components/MkContainer.vue";
import { useInterval } from "@/scripts/use-interval";

View File

@ -30,14 +30,13 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import * as os from "@/os";
import MkContainer from "@/components/MkContainer.vue";
import { useInterval } from "@/scripts/use-interval";

View File

@ -30,14 +30,13 @@
</template>
<script lang="ts" setup>
import type { Widget, WidgetComponentExpose } from "./widget";
import {
useWidgetPropsManager,
Widget,
WidgetComponentEmits,
WidgetComponentExpose,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import { GetFormResultType } from "@/scripts/form";
import type { GetFormResultType } from "@/scripts/form";
import { host } from "@/config";
const name = "serverInfo";

View File

@ -82,7 +82,7 @@
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount } from "vue";
import { onBeforeUnmount, onMounted } from "vue";
import { v4 as uuid } from "uuid";
const props = defineProps<{
@ -90,23 +90,23 @@ const props = defineProps<{
meta: any;
}>();
let viewBoxX: number = $ref(50);
let viewBoxY: number = $ref(30);
let stats: any[] = $ref([]);
const viewBoxX: number = $ref(50);
const viewBoxY: number = $ref(30);
const stats: any[] = $ref([]);
const cpuGradientId = uuid();
const cpuMaskId = uuid();
const memGradientId = uuid();
const memMaskId = uuid();
let cpuPolylinePoints: string = $ref("");
let memPolylinePoints: string = $ref("");
let cpuPolygonPoints: string = $ref("");
let memPolygonPoints: string = $ref("");
let cpuHeadX: any = $ref(null);
let cpuHeadY: any = $ref(null);
let memHeadX: any = $ref(null);
let memHeadY: any = $ref(null);
let cpuP: string = $ref("");
let memP: string = $ref("");
let cpuPolylinePoints: string = $ref(""),
memPolylinePoints: string = $ref(""),
cpuPolygonPoints: string = $ref(""),
memPolygonPoints: string = $ref(""),
cpuHeadX: any = $ref(null),
cpuHeadY: any = $ref(null),
memHeadX: any = $ref(null),
memHeadY: any = $ref(null),
cpuP: string = $ref(""),
memP: string = $ref("");
onMounted(() => {
props.connection.on("stats", onStats);
@ -125,11 +125,11 @@ function onStats(connStats) {
stats.push(connStats);
if (stats.length > 50) stats.shift();
let cpuPolylinePointsStats = stats.map((s, i) => [
const cpuPolylinePointsStats = stats.map((s, i) => [
viewBoxX - (stats.length - 1 - i),
(1 - s.cpu) * viewBoxY,
]);
let memPolylinePointsStats = stats.map((s, i) => [
const memPolylinePointsStats = stats.map((s, i) => [
viewBoxX - (stats.length - 1 - i),
(1 - s.mem.active / props.meta.mem.total) * viewBoxY,
]);

Some files were not shown because too many files have changed in this diff Show More