fix types
This commit is contained in:
parent
850201ff71
commit
62f5c84ca6
17 changed files with 222 additions and 131 deletions
|
@ -15,7 +15,7 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async () => {
|
export default define(meta, paramDef, async () => {
|
||||||
let release;
|
let release: unknown;
|
||||||
|
|
||||||
await fetch(
|
await fetch(
|
||||||
"https://firefish.dev/firefish/firefish/-/raw/develop/release.json",
|
"https://firefish.dev/firefish/firefish/-/raw/develop/release.json",
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { alert, api, popup, popupMenu, waiting } from "@/os";
|
||||||
import icon from "@/scripts/icon";
|
import icon from "@/scripts/icon";
|
||||||
import { del, get, set } from "@/scripts/idb-proxy";
|
import { del, get, set } from "@/scripts/idb-proxy";
|
||||||
import { reloadChannel, unisonReload } from "@/scripts/unison-reload";
|
import { reloadChannel, unisonReload } from "@/scripts/unison-reload";
|
||||||
|
import type { MenuButton, MenuUser } from "./types/menu";
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ export async function signOut() {
|
||||||
waiting();
|
waiting();
|
||||||
localStorage.removeItem("account");
|
localStorage.removeItem("account");
|
||||||
|
|
||||||
await removeAccount(me.id);
|
await removeAccount(me!.id);
|
||||||
|
|
||||||
const accounts = await getAccounts();
|
const accounts = await getAccounts();
|
||||||
|
|
||||||
|
@ -26,12 +27,9 @@ export async function signOut() {
|
||||||
const registration = await navigator.serviceWorker.ready;
|
const registration = await navigator.serviceWorker.ready;
|
||||||
const push = await registration.pushManager.getSubscription();
|
const push = await registration.pushManager.getSubscription();
|
||||||
if (push) {
|
if (push) {
|
||||||
await fetch(`${apiUrl}/sw/unregister`, {
|
await api("sw/unregister", {
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
i: me.token,
|
|
||||||
endpoint: push.endpoint,
|
endpoint: push.endpoint,
|
||||||
}),
|
i: me!.token, // FIXME: This parameter seems to be removable but I didn't test it
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,13 +115,13 @@ function showSuspendedDialog() {
|
||||||
|
|
||||||
export function updateAccount(accountData) {
|
export function updateAccount(accountData) {
|
||||||
for (const [key, value] of Object.entries(accountData)) {
|
for (const [key, value] of Object.entries(accountData)) {
|
||||||
me[key] = value;
|
me![key] = value;
|
||||||
}
|
}
|
||||||
localStorage.setItem("account", JSON.stringify(me));
|
localStorage.setItem("account", JSON.stringify(me));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function refreshAccount() {
|
export async function refreshAccount() {
|
||||||
const accountData = await fetchAccount(me.token);
|
const accountData = await fetchAccount(me!.token);
|
||||||
return updateAccount(accountData);
|
return updateAccount(accountData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +184,7 @@ export async function openAccountMenu(
|
||||||
|
|
||||||
async function switchAccount(account: entities.UserDetailed) {
|
async function switchAccount(account: entities.UserDetailed) {
|
||||||
const storedAccounts = await getAccounts();
|
const storedAccounts = await getAccounts();
|
||||||
const token = storedAccounts.find((x) => x.id === account.id).token;
|
const token = storedAccounts.find((x) => x.id === account.id)!.token;
|
||||||
switchAccountWithToken(token);
|
switchAccountWithToken(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,15 +193,15 @@ export async function openAccountMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
const storedAccounts = await getAccounts().then((accounts) =>
|
const storedAccounts = await getAccounts().then((accounts) =>
|
||||||
accounts.filter((x) => x.id !== me.id),
|
accounts.filter((x) => x.id !== me!.id),
|
||||||
);
|
);
|
||||||
const accountsPromise = api("users/show", {
|
const accountsPromise = api("users/show", {
|
||||||
userIds: storedAccounts.map((x) => x.id),
|
userIds: storedAccounts.map((x) => x.id),
|
||||||
});
|
});
|
||||||
|
|
||||||
function createItem(account: entities.UserDetailed) {
|
function createItem(account: entities.UserDetailed): MenuUser {
|
||||||
return {
|
return {
|
||||||
type: "user",
|
type: "user" as const,
|
||||||
user: account,
|
user: account,
|
||||||
active: opts.active != null ? opts.active === account.id : false,
|
active: opts.active != null ? opts.active === account.id : false,
|
||||||
action: () => {
|
action: () => {
|
||||||
|
@ -218,10 +216,14 @@ export async function openAccountMenu(
|
||||||
|
|
||||||
const accountItemPromises = storedAccounts.map(
|
const accountItemPromises = storedAccounts.map(
|
||||||
(a) =>
|
(a) =>
|
||||||
new Promise((res) => {
|
new Promise<MenuUser>((res) => {
|
||||||
accountsPromise.then((accounts) => {
|
accountsPromise.then((accounts) => {
|
||||||
const account = accounts.find((x) => x.id === a.id);
|
const account = accounts.find((x) => x.id === a.id);
|
||||||
if (account == null) return res(null);
|
if (account == null) {
|
||||||
|
// The user is deleted, remove it
|
||||||
|
removeAccount(a.id);
|
||||||
|
return res(null as unknown as MenuUser);
|
||||||
|
}
|
||||||
res(createItem(account));
|
res(createItem(account));
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -230,11 +232,10 @@ export async function openAccountMenu(
|
||||||
if (opts.withExtraOperation) {
|
if (opts.withExtraOperation) {
|
||||||
popupMenu(
|
popupMenu(
|
||||||
[
|
[
|
||||||
...[
|
|
||||||
...(isMobile ?? false
|
...(isMobile ?? false
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
type: "parent",
|
type: "parent" as const,
|
||||||
icon: `${icon("ph-plus")}`,
|
icon: `${icon("ph-plus")}`,
|
||||||
text: i18n.ts.addAccount,
|
text: i18n.ts.addAccount,
|
||||||
children: [
|
children: [
|
||||||
|
@ -255,28 +256,28 @@ export async function openAccountMenu(
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
type: "link",
|
type: "link" as const,
|
||||||
text: i18n.ts.profile,
|
text: i18n.ts.profile,
|
||||||
to: `/@${me.username}`,
|
to: `/@${me!.username}`,
|
||||||
avatar: me,
|
avatar: me!,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
]),
|
]),
|
||||||
...(opts.includeCurrentAccount ? [createItem(me)] : []),
|
...(opts.includeCurrentAccount ? [createItem(me!)] : []),
|
||||||
...accountItemPromises,
|
...accountItemPromises,
|
||||||
...(isMobile ?? false
|
...(isMobile ?? false
|
||||||
? [
|
? [
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
type: "link",
|
type: "link" as const,
|
||||||
text: i18n.ts.profile,
|
text: i18n.ts.profile,
|
||||||
to: `/@${me.username}`,
|
to: `/@${me!.username}`,
|
||||||
avatar: me,
|
avatar: me!,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
type: "parent",
|
type: "parent" as const,
|
||||||
icon: `${icon("ph-plus")}`,
|
icon: `${icon("ph-plus")}`,
|
||||||
text: i18n.ts.addAccount,
|
text: i18n.ts.addAccount,
|
||||||
children: [
|
children: [
|
||||||
|
@ -296,8 +297,7 @@ export async function openAccountMenu(
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
],
|
(ev.currentTarget ?? ev.target) as HTMLElement,
|
||||||
ev.currentTarget ?? ev.target,
|
|
||||||
{
|
{
|
||||||
align: "left",
|
align: "left",
|
||||||
},
|
},
|
||||||
|
@ -305,10 +305,10 @@ export async function openAccountMenu(
|
||||||
} else {
|
} else {
|
||||||
popupMenu(
|
popupMenu(
|
||||||
[
|
[
|
||||||
...(opts.includeCurrentAccount ? [createItem(me)] : []),
|
...(opts.includeCurrentAccount ? [createItem(me!)] : []),
|
||||||
...accountItemPromises,
|
...accountItemPromises,
|
||||||
],
|
],
|
||||||
ev.currentTarget ?? ev.target,
|
(ev.currentTarget ?? ev.target) as HTMLElement,
|
||||||
{
|
{
|
||||||
align: "left",
|
align: "left",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :z-priority="'middle'" @closed="$emit('closed')">
|
<MkModal ref="modal" :z-priority="'middle'" @closed="emit('closed')">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div :class="$style.title">
|
<div :class="$style.title">
|
||||||
<MkSparkle v-if="isGoodNews">{{ title }}</MkSparkle>
|
<MkSparkle v-if="isGoodNews">{{ title }}</MkSparkle>
|
||||||
|
@ -41,6 +41,10 @@ const props = defineProps<{
|
||||||
announcement: entities.Announcement;
|
announcement: entities.Announcement;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
closed: [];
|
||||||
|
}>();
|
||||||
|
|
||||||
const { id, text, title, imageUrl, isGoodNews } = props.announcement;
|
const { id, text, title, imageUrl, isGoodNews } = props.announcement;
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :z-priority="'middle'" @closed="$emit('closed')">
|
<MkModal ref="modal" :z-priority="'middle'" @closed="emit('closed')">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<p :class="$style.title">
|
<p :class="$style.title">
|
||||||
{{ i18n.ts.youHaveUnreadAnnouncements }}
|
{{ i18n.ts.youHaveUnreadAnnouncements }}
|
||||||
|
@ -21,6 +21,10 @@ import MkModal from "@/components/MkModal.vue";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
closed: [];
|
||||||
|
}>();
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
const checkAnnouncements = () => {
|
const checkAnnouncements = () => {
|
||||||
modal.value!.close();
|
modal.value!.close();
|
||||||
|
|
|
@ -160,7 +160,7 @@ const hCaptchaResponse = ref(null);
|
||||||
const reCaptchaResponse = ref(null);
|
const reCaptchaResponse = ref(null);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: "login", v: any): void;
|
login: [v: { id: string; i: string }];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
|
@ -30,7 +30,7 @@ withDefaults(
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: "done"): void;
|
(ev: "done", res: { id: string; i: string }): void;
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
(ev: "cancelled"): void;
|
(ev: "cancelled"): void;
|
||||||
}>();
|
}>();
|
||||||
|
@ -39,11 +39,11 @@ const dialog = ref<InstanceType<typeof XModalWindow>>();
|
||||||
|
|
||||||
function onClose() {
|
function onClose() {
|
||||||
emit("cancelled");
|
emit("cancelled");
|
||||||
dialog.value.close();
|
dialog.value!.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLogin(res) {
|
function onLogin(res: { id: string; i: string }) {
|
||||||
emit("done", res);
|
emit("done", res);
|
||||||
dialog.value.close();
|
dialog.value!.close();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -248,7 +248,7 @@
|
||||||
v-model="hCaptchaResponse"
|
v-model="hCaptchaResponse"
|
||||||
class="_formBlock captcha"
|
class="_formBlock captcha"
|
||||||
provider="hcaptcha"
|
provider="hcaptcha"
|
||||||
:sitekey="instance.hcaptchaSiteKey"
|
:sitekey="instance.hcaptchaSiteKey!"
|
||||||
/>
|
/>
|
||||||
<MkCaptcha
|
<MkCaptcha
|
||||||
v-if="instance.enableRecaptcha"
|
v-if="instance.enableRecaptcha"
|
||||||
|
@ -256,7 +256,7 @@
|
||||||
v-model="reCaptchaResponse"
|
v-model="reCaptchaResponse"
|
||||||
class="_formBlock captcha"
|
class="_formBlock captcha"
|
||||||
provider="recaptcha"
|
provider="recaptcha"
|
||||||
:sitekey="instance.recaptchaSiteKey"
|
:sitekey="instance.recaptchaSiteKey!"
|
||||||
/>
|
/>
|
||||||
<MkButton
|
<MkButton
|
||||||
class="_formBlock"
|
class="_formBlock"
|
||||||
|
@ -296,7 +296,7 @@ const props = withDefaults(
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: "signup", user: Record<string, any>): void;
|
(ev: "signup", user: { id: string; i: string }): void;
|
||||||
(ev: "signupEmailPending"): void;
|
(ev: "signupEmailPending"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,13 @@ withDefaults(
|
||||||
);
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: "done"): void;
|
(ev: "done", res: { id: string; i: string }): void;
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = ref<InstanceType<typeof XModalWindow>>();
|
const dialog = ref<InstanceType<typeof XModalWindow>>();
|
||||||
|
|
||||||
function onSignup(res) {
|
function onSignup(res: { id: string; i: string }) {
|
||||||
emit("done", res);
|
emit("done", res);
|
||||||
dialog.value?.close();
|
dialog.value?.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<MkModal
|
<MkModal
|
||||||
ref="modal"
|
ref="modal"
|
||||||
:z-priority="'middle'"
|
:z-priority="'middle'"
|
||||||
@click="$refs.modal.close()"
|
@click="modal!.close()"
|
||||||
@closed="$emit('closed')"
|
@closed="emit('closed')"
|
||||||
>
|
>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div :class="$style.title">
|
<div :class="$style.title">
|
||||||
|
@ -11,8 +11,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.version">✨ {{ version }} 🚀</div>
|
<div :class="$style.version">✨ {{ version }} 🚀</div>
|
||||||
<div v-if="newRelease" :class="$style.releaseNotes">
|
<div v-if="newRelease" :class="$style.releaseNotes">
|
||||||
<Mfm :text="data.notes" />
|
<Mfm :text="data?.notes ?? ''" />
|
||||||
<div v-if="data.screenshots.length > 0" style="max-width: 500">
|
<div v-if="data?.screenshots && data.screenshots.length > 0" style="max-width: 500">
|
||||||
<img
|
<img
|
||||||
v-for="i in data.screenshots"
|
v-for="i in data.screenshots"
|
||||||
:key="i"
|
:key="i"
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
:class="$style.gotIt"
|
:class="$style.gotIt"
|
||||||
primary
|
primary
|
||||||
full
|
full
|
||||||
@click="$refs.modal.close()"
|
@click="modal!.close()"
|
||||||
>{{ i18n.ts.gotIt }}</MkButton
|
>{{ i18n.ts.gotIt }}</MkButton
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -40,11 +40,16 @@ import MkButton from "@/components/MkButton.vue";
|
||||||
import { version } from "@/config";
|
import { version } from "@/config";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
import type { Endpoints } from "firefish-js";
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
closed: [];
|
||||||
|
}>();
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
const newRelease = ref(false);
|
const newRelease = ref(false);
|
||||||
const data = ref(Object);
|
const data = ref<Endpoints["release"]["res"] | null>(null);
|
||||||
|
|
||||||
os.api("release").then((res) => {
|
os.api("release").then((res) => {
|
||||||
data.value = res;
|
data.value = res;
|
||||||
|
@ -52,7 +57,7 @@ os.api("release").then((res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Version: ${version}`);
|
console.log(`Version: ${version}`);
|
||||||
console.log(`Data version: ${data.value.version}`);
|
console.log(`Data version: ${data.value?.version}`);
|
||||||
console.log(newRelease.value);
|
console.log(newRelease.value);
|
||||||
console.log(data.value);
|
console.log(data.value);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { markRaw } from "vue";
|
import { markRaw } from "vue";
|
||||||
import { locale } from "@/config";
|
import { locale } from "@/config";
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: temporary use any
|
||||||
class I18n<T extends Record<string, any>> {
|
class I18n<T extends Record<string, any>> {
|
||||||
public ts: T;
|
public ts: T;
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,12 @@ function checkForSplash() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 変なバージョン文字列来るとcompareVersionsでエラーになるため
|
// 変なバージョン文字列来るとcompareVersionsでエラーになるため
|
||||||
if (lastVersion < version && defaultStore.state.showUpdates) {
|
// If a strange version string comes, an error will occur in compareVersions.
|
||||||
|
if (
|
||||||
|
lastVersion != null &&
|
||||||
|
lastVersion < version &&
|
||||||
|
defaultStore.state.showUpdates
|
||||||
|
) {
|
||||||
// ログインしてる場合だけ
|
// ログインしてる場合だけ
|
||||||
if (me) {
|
if (me) {
|
||||||
popup(
|
popup(
|
||||||
|
@ -281,7 +286,7 @@ function checkForSplash() {
|
||||||
"closed",
|
"closed",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
unreadAnnouncements.forEach((item) => {
|
for (const item of unreadAnnouncements) {
|
||||||
if (item.showPopup)
|
if (item.showPopup)
|
||||||
popup(
|
popup(
|
||||||
defineAsyncComponent(
|
defineAsyncComponent(
|
||||||
|
@ -291,7 +296,7 @@ function checkForSplash() {
|
||||||
{},
|
{},
|
||||||
"closed",
|
"closed",
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => console.log(err));
|
.catch((err) => console.log(err));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// NIRAX --- A lightweight router
|
// NIRAX --- A lightweight router
|
||||||
|
|
||||||
import { EventEmitter } from "eventemitter3";
|
import { EventEmitter } from "eventemitter3";
|
||||||
import type { Component, ShallowRef } from "vue";
|
import type { Component } from "vue";
|
||||||
import { shallowRef } from "vue";
|
import { shallowRef } from "vue";
|
||||||
import { safeURIDecode } from "@/scripts/safe-uri-decode";
|
import { safeURIDecode } from "@/scripts/safe-uri-decode";
|
||||||
import { pleaseLogin } from "@/scripts/please-login";
|
import { pleaseLogin } from "@/scripts/please-login";
|
||||||
|
@ -36,6 +36,7 @@ export interface Resolved {
|
||||||
function parsePath(path: string): ParsedPath {
|
function parsePath(path: string): ParsedPath {
|
||||||
const res = [] as ParsedPath;
|
const res = [] as ParsedPath;
|
||||||
|
|
||||||
|
// biome-ignore lint/style/noParameterAssign: assign it intentionally
|
||||||
path = path.substring(1);
|
path = path.substring(1);
|
||||||
|
|
||||||
for (const part of path.split("/")) {
|
for (const part of path.split("/")) {
|
||||||
|
@ -76,13 +77,13 @@ export class Router extends EventEmitter<{
|
||||||
same: () => void;
|
same: () => void;
|
||||||
}> {
|
}> {
|
||||||
private routes: RouteDef[];
|
private routes: RouteDef[];
|
||||||
public current: Resolved;
|
public current!: Resolved; // It is assigned in this.navigate
|
||||||
public currentRef: ShallowRef<Resolved> = shallowRef();
|
public currentRef = shallowRef<Resolved>();
|
||||||
public currentRoute: ShallowRef<RouteDef> = shallowRef();
|
public currentRoute = shallowRef<RouteDef>();
|
||||||
private currentPath: string;
|
private currentPath: string;
|
||||||
private currentKey = Date.now().toString();
|
private currentKey = Date.now().toString();
|
||||||
|
|
||||||
public navHook: ((path: string, flag?: any) => boolean) | null = null;
|
public navHook: ((path: string, flag?: unknown) => boolean) | null = null;
|
||||||
|
|
||||||
constructor(routes: Router["routes"], currentPath: Router["currentPath"]) {
|
constructor(routes: Router["routes"], currentPath: Router["currentPath"]) {
|
||||||
super();
|
super();
|
||||||
|
@ -92,9 +93,10 @@ export class Router extends EventEmitter<{
|
||||||
this.navigate(currentPath, null, false);
|
this.navigate(currentPath, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public resolve(path: string): Resolved | null {
|
public resolve(_path: string): Resolved | null {
|
||||||
let queryString: string | null = null;
|
let queryString: string | null = null;
|
||||||
let hash: string | null = null;
|
let hash: string | null = null;
|
||||||
|
let path = _path;
|
||||||
if (path[0] === "/") path = path.substring(1);
|
if (path[0] === "/") path = path.substring(1);
|
||||||
if (path.includes("#")) {
|
if (path.includes("#")) {
|
||||||
hash = path.substring(path.indexOf("#") + 1);
|
hash = path.substring(path.indexOf("#") + 1);
|
||||||
|
@ -168,9 +170,16 @@ export class Router extends EventEmitter<{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.query != null && queryString != null) {
|
if (route.query != null && queryString != null) {
|
||||||
const queryObject = [
|
// const queryObject = [
|
||||||
...new URLSearchParams(queryString).entries(),
|
// ...new URLSearchParams(queryString).entries(),
|
||||||
].reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {});
|
// ].reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {});
|
||||||
|
|
||||||
|
const queryObject: Record<string, string> = Object.assign(
|
||||||
|
{},
|
||||||
|
...[...new URLSearchParams(queryString).entries()].map(
|
||||||
|
(entry) => ({ [entry[0]]: entry[1] }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
for (const q in route.query) {
|
for (const q in route.query) {
|
||||||
const as = route.query[q];
|
const as = route.query[q];
|
||||||
|
@ -227,6 +236,7 @@ export class Router extends EventEmitter<{
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSamePath = beforePath === path;
|
const isSamePath = beforePath === path;
|
||||||
|
// biome-ignore lint/style/noParameterAssign: assign it intentionally
|
||||||
if (isSamePath && key == null) key = this.currentKey;
|
if (isSamePath && key == null) key = this.currentKey;
|
||||||
this.current = res;
|
this.current = res;
|
||||||
this.currentRef.value = res;
|
this.currentRef.value = res;
|
||||||
|
@ -253,7 +263,7 @@ export class Router extends EventEmitter<{
|
||||||
return this.currentKey;
|
return this.currentKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public push(path: string, flag?: any) {
|
public push(path: string, flag?: unknown) {
|
||||||
const beforePath = this.currentPath;
|
const beforePath = this.currentPath;
|
||||||
if (path === beforePath) {
|
if (path === beforePath) {
|
||||||
this.emit("same");
|
this.emit("same");
|
||||||
|
|
|
@ -893,9 +893,6 @@ export async function openEmojiPicker(
|
||||||
...opts,
|
...opts,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
chosen: (emoji) => {
|
|
||||||
insertTextAtCursor(activeTextarea, emoji);
|
|
||||||
},
|
|
||||||
done: (emoji) => {
|
done: (emoji) => {
|
||||||
insertTextAtCursor(activeTextarea, emoji);
|
insertTextAtCursor(activeTextarea, emoji);
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
i18n.ts._accountDelete.sendEmail
|
i18n.ts._accountDelete.sendEmail
|
||||||
}}</FormInfo>
|
}}</FormInfo>
|
||||||
<FormButton
|
<FormButton
|
||||||
v-if="!me.isDeleted"
|
v-if="!me!.isDeleted"
|
||||||
danger
|
danger
|
||||||
class="_formBlock"
|
class="_formBlock"
|
||||||
@click="deleteAccount"
|
@click="deleteAccount"
|
||||||
|
@ -27,6 +27,7 @@ import { signOut } from "@/account";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||||
import icon from "@/scripts/icon";
|
import icon from "@/scripts/icon";
|
||||||
|
import { me } from "@/me";
|
||||||
|
|
||||||
async function deleteAccount() {
|
async function deleteAccount() {
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,7 +42,20 @@ export function install(plugin) {
|
||||||
aiscript.exec(parser.parse(plugin.src));
|
aiscript.exec(parser.parse(plugin.src));
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPluginEnv(opts) {
|
interface Plugin {
|
||||||
|
config?: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
default: unknown;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
configData: Record<string, unknown>;
|
||||||
|
token: string;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPluginEnv(opts: { plugin: Plugin; storageKey: string }) {
|
||||||
const config = new Map<string, values.Value>();
|
const config = new Map<string, values.Value>();
|
||||||
for (const [k, v] of Object.entries(opts.plugin.config ?? {})) {
|
for (const [k, v] of Object.entries(opts.plugin.config ?? {})) {
|
||||||
config.set(
|
config.set(
|
||||||
|
@ -172,7 +185,7 @@ function registerNoteAction({ pluginId, title, handler }) {
|
||||||
if (!pluginContext) {
|
if (!pluginContext) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pluginContext.execFn(handler, [utils.jsToVal(user)]);
|
pluginContext.execFn(handler, [utils.jsToVal(note)]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -205,16 +218,18 @@ function registerNotePostInterruptor({ pluginId, handler }) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: where is pageViewInterruptors?
|
||||||
|
// This function currently can't do anything
|
||||||
function registerPageViewInterruptor({ pluginId, handler }): void {
|
function registerPageViewInterruptor({ pluginId, handler }): void {
|
||||||
pageViewInterruptors.push({
|
// pageViewInterruptors.push({
|
||||||
handler: async (page) => {
|
// handler: async (page) => {
|
||||||
const pluginContext = pluginContexts.get(pluginId);
|
// const pluginContext = pluginContexts.get(pluginId);
|
||||||
if (!pluginContext) {
|
// if (!pluginContext) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
return utils.valToJs(
|
// return utils.valToJs(
|
||||||
await pluginContext.execFn(handler, [utils.jsToVal(page)]),
|
// await pluginContext.execFn(handler, [utils.jsToVal(page)]),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
|
@ -362,6 +362,16 @@ export type Endpoints = {
|
||||||
res: DriveFile[];
|
res: DriveFile[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"email-address/available": {
|
||||||
|
req: {
|
||||||
|
emailAddress: string;
|
||||||
|
};
|
||||||
|
res: {
|
||||||
|
available?: boolean;
|
||||||
|
reason: string | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// endpoint
|
// endpoint
|
||||||
endpoint: {
|
endpoint: {
|
||||||
req: { endpoint: string };
|
req: { endpoint: string };
|
||||||
|
@ -893,6 +903,16 @@ export type Endpoints = {
|
||||||
// promo
|
// promo
|
||||||
"promo/read": { req: TODO; res: TODO };
|
"promo/read": { req: TODO; res: TODO };
|
||||||
|
|
||||||
|
// release
|
||||||
|
release: {
|
||||||
|
req: null;
|
||||||
|
res: {
|
||||||
|
version: string;
|
||||||
|
notes: string;
|
||||||
|
screenshots: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// request-reset-password
|
// request-reset-password
|
||||||
"request-reset-password": {
|
"request-reset-password": {
|
||||||
req: { username: string; email: string };
|
req: { username: string; email: string };
|
||||||
|
@ -915,8 +935,36 @@ export type Endpoints = {
|
||||||
// ck specific
|
// ck specific
|
||||||
"latest-version": { req: NoParams; res: TODO };
|
"latest-version": { req: NoParams; res: TODO };
|
||||||
|
|
||||||
|
// signin
|
||||||
|
signin: {
|
||||||
|
req: {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
"hcaptcha-response"?: null | string;
|
||||||
|
"g-recaptcha-response"?: null | string;
|
||||||
|
};
|
||||||
|
res:
|
||||||
|
| {
|
||||||
|
id: User["id"];
|
||||||
|
i: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
challenge: string;
|
||||||
|
challengeId: string;
|
||||||
|
securityKeys: {
|
||||||
|
id: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// sw
|
// sw
|
||||||
"sw/register": { req: TODO; res: TODO };
|
"sw/register": { req: TODO; res: TODO };
|
||||||
|
"sw/unregister": {
|
||||||
|
req: {
|
||||||
|
endpoint: string;
|
||||||
|
};
|
||||||
|
res: null;
|
||||||
|
};
|
||||||
|
|
||||||
// username
|
// username
|
||||||
"username/available": {
|
"username/available": {
|
||||||
|
|
|
@ -116,6 +116,7 @@ export type MeDetailed = UserDetailed & {
|
||||||
preventAiLearning: boolean;
|
preventAiLearning: boolean;
|
||||||
receiveAnnouncementEmail: boolean;
|
receiveAnnouncementEmail: boolean;
|
||||||
usePasswordLessLogin: boolean;
|
usePasswordLessLogin: boolean;
|
||||||
|
token: string;
|
||||||
[other: string]: any;
|
[other: string]: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -479,7 +480,7 @@ export type Announcement = {
|
||||||
imageUrl: string | null;
|
imageUrl: string | null;
|
||||||
isRead?: boolean;
|
isRead?: boolean;
|
||||||
isGoodNews: boolean;
|
isGoodNews: boolean;
|
||||||
showPopUp: boolean;
|
showPopup: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Antenna = {
|
export type Antenna = {
|
||||||
|
|
Loading…
Reference in a new issue