This commit is contained in:
syuilo 2025-08-26 17:31:36 +09:00
parent 203296b9cb
commit 69bbac013a
13 changed files with 67 additions and 39 deletions

View File

@ -73,8 +73,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
updatedAt: new Date(), updatedAt: new Date(),
...Object.fromEntries( ...Object.fromEntries(
Object.entries(ps).filter( Object.entries(ps).filter(
([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key) ([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key),
) ),
), ),
}); });
}); });

View File

@ -23,7 +23,7 @@ export async function getAccounts(): Promise<{
host: string; host: string;
id: Misskey.entities.User['id']; id: Misskey.entities.User['id'];
username: Misskey.entities.User['username']; username: Misskey.entities.User['username'];
user?: Misskey.entities.User | null; user?: Misskey.entities.MeDetailed | null;
token: string | null; token: string | null;
}[]> { }[]> {
const tokens = store.s.accountTokens; const tokens = store.s.accountTokens;
@ -38,7 +38,7 @@ export async function getAccounts(): Promise<{
})); }));
} }
async function addAccount(host: string, user: Misskey.entities.User, token: AccountWithToken['token']) { async function addAccount(host: string, user: Misskey.entities.MeDetailed, token: AccountWithToken['token']) {
if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) { if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) {
store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token }); store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token });
store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + user.id]: user }); store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + user.id]: user });
@ -149,9 +149,10 @@ export function updateCurrentAccountPartial(accountData: Partial<Misskey.entitie
export async function refreshCurrentAccount() { export async function refreshCurrentAccount() {
if (!$i) return; if (!$i) return;
const me = $i;
return fetchAccount($i.token, $i.id).then(updateCurrentAccount).catch(reason => { return fetchAccount($i.token, $i.id).then(updateCurrentAccount).catch(reason => {
if (reason === isAccountDeleted) { if (reason === isAccountDeleted) {
removeAccount(host, $i.id); removeAccount(host, me.id);
if (Object.keys(store.s.accountTokens).length > 0) { if (Object.keys(store.s.accountTokens).length > 0) {
login(Object.values(store.s.accountTokens)[0]); login(Object.values(store.s.accountTokens)[0]);
} else { } else {
@ -214,19 +215,37 @@ export async function openAccountMenu(opts: {
includeCurrentAccount?: boolean; includeCurrentAccount?: boolean;
withExtraOperation: boolean; withExtraOperation: boolean;
active?: Misskey.entities.User['id']; active?: Misskey.entities.User['id'];
onChoose?: (account: Misskey.entities.User) => void; onChoose?: (account: Misskey.entities.MeDetailed) => void;
}, ev: MouseEvent) { }, ev: MouseEvent) {
if (!$i) return; if (!$i) return;
const me = $i;
function createItem(host: string, id: Misskey.entities.User['id'], username: Misskey.entities.User['username'], account: Misskey.entities.User | null | undefined, token: string): MenuItem { const callback = opts.onChoose;
function createItem(host: string, id: Misskey.entities.User['id'], username: Misskey.entities.User['username'], account: Misskey.entities.MeDetailed | null | undefined, token: string | null): MenuItem {
if (account) { if (account) {
return { return {
type: 'user' as const, type: 'user' as const,
user: account, user: account,
active: opts.active != null ? opts.active === id : false, active: opts.active != null ? opts.active === id : false,
action: async () => { action: async () => {
if (opts.onChoose) { if (callback) {
opts.onChoose(account); callback(account);
} else {
switchAccount(host, id);
}
},
};
} else if (token != null) {
return {
type: 'button' as const,
text: username,
active: opts.active != null ? opts.active === id : false,
action: async () => {
if (callback) {
fetchAccount(token, id).then(account => {
callback(account);
});
} else { } else {
switchAccount(host, id); switchAccount(host, id);
} }
@ -238,13 +257,7 @@ export async function openAccountMenu(opts: {
text: username, text: username,
active: opts.active != null ? opts.active === id : false, active: opts.active != null ? opts.active === id : false,
action: async () => { action: async () => {
if (opts.onChoose) { // TODO
fetchAccount(token, id).then(account => {
opts.onChoose(account);
});
} else {
switchAccount(host, id);
}
}, },
}; };
} }
@ -253,7 +266,7 @@ export async function openAccountMenu(opts: {
const menuItems: MenuItem[] = []; const menuItems: MenuItem[] = [];
// TODO: $iのホストも比較したいけど通常null // TODO: $iのホストも比較したいけど通常null
const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id))).map(a => createItem(a.host, a.id, a.username, a.user, a.token)); const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.id !== me.id))).map(a => createItem(a.host, a.id, a.username, a.user, a.token));
if (opts.withExtraOperation) { if (opts.withExtraOperation) {
menuItems.push({ menuItems.push({

View File

@ -39,10 +39,12 @@ const el = ref<HTMLElement | { $el: HTMLElement }>();
if (isEnabledUrlPreview.value) { if (isEnabledUrlPreview.value) {
useTooltip(el, (showing) => { useTooltip(el, (showing) => {
const anchorElement = el.value instanceof HTMLElement ? el.value : el.value?.$el;
if (anchorElement == null) return;
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), { const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUrlPreviewPopup.vue')), {
showing, showing,
url: props.url, url: props.url,
anchorElement: el.value instanceof HTMLElement ? el.value : el.value?.$el, anchorElement: anchorElement,
}, { }, {
closed: () => dispose(), closed: () => dispose(),
}); });

View File

@ -654,7 +654,7 @@ function showRenoteMenu(): void {
getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote), getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote),
{ type: 'divider' }, { type: 'divider' },
getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote), getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote),
($i?.isModerator || $i?.isAdmin) ? getUnrenote() : undefined, ...(($i?.isModerator || $i?.isAdmin) ? [getUnrenote()] : []),
], renoteTime.value); ], renoteTime.value);
} }
} }

View File

@ -392,6 +392,9 @@ const reactionsPaginator = markRaw(new Paginator('notes/reactions', {
})); }));
useTooltip(renoteButton, async (showing) => { useTooltip(renoteButton, async (showing) => {
const anchorElement = renoteButton.value;
if (anchorElement == null) return;
const renotes = await misskeyApi('notes/renotes', { const renotes = await misskeyApi('notes/renotes', {
noteId: appearNote.id, noteId: appearNote.id,
limit: 11, limit: 11,
@ -405,7 +408,7 @@ useTooltip(renoteButton, async (showing) => {
showing, showing,
users, users,
count: appearNote.renoteCount, count: appearNote.renoteCount,
anchorElement: renoteButton.value, anchorElement: anchorElement,
}, { }, {
closed: () => dispose(), closed: () => dispose(),
}); });

View File

@ -57,7 +57,7 @@ async function _close() {
modal.value?.close(); modal.value?.close();
} }
function onEsc(ev: KeyboardEvent) { function onEsc() {
_close(); _close();
} }

View File

@ -684,7 +684,7 @@ export async function cropImageFile(imageFile: File | Blob, options: {
}); });
} }
export function popupMenu(items: MenuItem[], anchorElement?: HTMLElement | EventTarget | null, options?: { export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElement | EventTarget | null, options?: {
align?: string; align?: string;
width?: number; width?: number;
onClosing?: () => void; onClosing?: () => void;
@ -696,7 +696,7 @@ export function popupMenu(items: MenuItem[], anchorElement?: HTMLElement | Event
let returnFocusTo = getHTMLElementOrNull(anchorElement) ?? getHTMLElementOrNull(window.document.activeElement); let returnFocusTo = getHTMLElementOrNull(anchorElement) ?? getHTMLElementOrNull(window.document.activeElement);
return new Promise(resolve => nextTick(() => { return new Promise(resolve => nextTick(() => {
const { dispose } = popup(MkPopupMenu, { const { dispose } = popup(MkPopupMenu, {
items, items: items.filter(x => x != null),
anchorElement, anchorElement,
width: options?.width, width: options?.width,
align: options?.align, align: options?.align,

View File

@ -383,7 +383,7 @@ if (props.id) {
const title = ref(flash.value?.title ?? 'New Play'); const title = ref(flash.value?.title ?? 'New Play');
const summary = ref(flash.value?.summary ?? ''); const summary = ref(flash.value?.summary ?? '');
const permissions = ref(flash.value?.permissions ?? []); const permissions = ref([]); // not implemented yet
const visibility = ref<'private' | 'public'>(flash.value?.visibility ?? 'public'); const visibility = ref<'private' | 'public'>(flash.value?.visibility ?? 'public');
const script = ref(flash.value?.script ?? PRESET_DEFAULT); const script = ref(flash.value?.script ?? PRESET_DEFAULT);
@ -412,9 +412,9 @@ function selectPreset(ev: MouseEvent) {
} }
async function save() { async function save() {
if (flash.value) { if (flash.value != null) {
os.apiWithDialog('flash/update', { os.apiWithDialog('flash/update', {
flashId: props.id, flashId: flash.value.id,
title: title.value, title: title.value,
summary: summary.value, summary: summary.value,
permissions: permissions.value, permissions: permissions.value,
@ -448,6 +448,8 @@ function show() {
} }
async function del() { async function del() {
if (flash.value == null) return;
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'warning', type: 'warning',
text: i18n.tsx.deleteAreYouSure({ x: flash.value.title }), text: i18n.tsx.deleteAreYouSure({ x: flash.value.title }),
@ -455,7 +457,7 @@ async function del() {
if (canceled) return; if (canceled) return;
await os.apiWithDialog('flash/delete', { await os.apiWithDialog('flash/delete', {
flashId: props.id, flashId: flash.value.id,
}); });
router.push('/play'); router.push('/play');
} }
@ -468,6 +470,7 @@ definePage(() => ({
title: flash.value ? `${i18n.ts._play.edit}: ${flash.value.title}` : i18n.ts._play.new, title: flash.value ? `${i18n.ts._play.edit}: ${flash.value.title}` : i18n.ts._play.new,
})); }));
</script> </script>
<style lang="scss" module> <style lang="scss" module>
.footer { .footer {
backdrop-filter: var(--MI-blur, blur(15px)); backdrop-filter: var(--MI-blur, blur(15px));

View File

@ -106,7 +106,7 @@ export const store = markRaw(new Pizzax('base', {
}, },
accountInfos: { accountInfos: {
where: 'device', where: 'device',
default: {} as Record<string, Misskey.entities.User>, // host/userId, user default: {} as Record<string, Misskey.entities.MeDetailed>, // host/userId, user
}, },
enablePreferencesAutoCloudBackup: { enablePreferencesAutoCloudBackup: {

View File

@ -18,7 +18,7 @@ export type MenuAction = (ev: MouseEvent) => void;
export interface MenuButton { export interface MenuButton {
type?: 'button'; type?: 'button';
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
icon?: string; icon?: string;
indicate?: boolean; indicate?: boolean;
danger?: boolean; danger?: boolean;
@ -38,14 +38,14 @@ export interface MenuDivider extends MenuBase {
export interface MenuLabel extends MenuBase { export interface MenuLabel extends MenuBase {
type: 'label'; type: 'label';
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
} }
export interface MenuLink extends MenuBase { export interface MenuLink extends MenuBase {
type: 'link'; type: 'link';
to: string; to: string;
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
icon?: string; icon?: string;
indicate?: boolean; indicate?: boolean;
avatar?: Misskey.entities.User; avatar?: Misskey.entities.User;
@ -57,7 +57,7 @@ export interface MenuA extends MenuBase {
target?: string; target?: string;
download?: string; download?: string;
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
icon?: string; icon?: string;
indicate?: boolean; indicate?: boolean;
} }
@ -74,7 +74,7 @@ export interface MenuSwitch extends MenuBase {
type: 'switch'; type: 'switch';
ref: Ref<boolean>; ref: Ref<boolean>;
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
icon?: string; icon?: string;
disabled?: boolean | Ref<boolean>; disabled?: boolean | Ref<boolean>;
} }
@ -82,7 +82,7 @@ export interface MenuSwitch extends MenuBase {
export interface MenuRadio extends MenuBase { export interface MenuRadio extends MenuBase {
type: 'radio'; type: 'radio';
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
icon?: string; icon?: string;
ref: Ref<MenuRadioOptionsDef[keyof MenuRadioOptionsDef]>; ref: Ref<MenuRadioOptionsDef[keyof MenuRadioOptionsDef]>;
options: MenuRadioOptionsDef; options: MenuRadioOptionsDef;
@ -92,7 +92,7 @@ export interface MenuRadio extends MenuBase {
export interface MenuRadioOption extends MenuBase { export interface MenuRadioOption extends MenuBase {
type: 'radioOption'; type: 'radioOption';
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
action: MenuAction; action: MenuAction;
active?: boolean | ComputedRef<boolean>; active?: boolean | ComputedRef<boolean>;
} }
@ -106,7 +106,7 @@ export interface MenuComponent<T extends Component = any> extends MenuBase {
export interface MenuParent extends MenuBase { export interface MenuParent extends MenuBase {
type: 'parent'; type: 'parent';
text: Text; text: Text;
caption?: Text; caption?: Text | null | undefined | ComputedRef<null | undefined>;
icon?: string; icon?: string;
children: MenuItem[] | (() => Promise<MenuItem[]> | MenuItem[]); children: MenuItem[] | (() => Promise<MenuItem[]> | MenuItem[]);
} }

View File

@ -8,7 +8,14 @@ import * as Misskey from 'misskey-js';
export interface PostFormProps { export interface PostFormProps {
reply?: Misskey.entities.Note | null; reply?: Misskey.entities.Note | null;
renote?: Misskey.entities.Note | null; renote?: Misskey.entities.Note | null;
channel?: Misskey.entities.Channel | null; // TODO channel?: {
id: string;
name: string;
color: string;
isSensitive: boolean;
allowRenoteToExternal: boolean;
userId: string | null;
} | null;
mention?: Misskey.entities.User; mention?: Misskey.entities.User;
specified?: Misskey.entities.UserDetailed; specified?: Misskey.entities.UserDetailed;
initialText?: string; initialText?: string;

View File

@ -233,7 +233,7 @@ function select(anchorElement: HTMLElement | EventTarget | null, label: string |
os.popupMenu([label ? { os.popupMenu([label ? {
text: label, text: label,
type: 'label', type: 'label',
} : undefined, { } : null, {
text: i18n.ts.upload, text: i18n.ts.upload,
icon: 'ti ti-upload', icon: 'ti ti-upload',
action: () => chooseFileFromPcAndUpload({ multiple, features }).then(files => res(files)), action: () => chooseFileFromPcAndUpload({ multiple, features }).then(files => res(files)),

View File

@ -13,7 +13,7 @@ const removeHash = (x: string) => x.replace(/#[^#]*$/, '');
export function extractUrlFromMfm(nodes: mfm.MfmNode[], respectSilentFlag = true): string[] { export function extractUrlFromMfm(nodes: mfm.MfmNode[], respectSilentFlag = true): string[] {
const urlNodes = mfm.extract(nodes, (node) => { const urlNodes = mfm.extract(nodes, (node) => {
return (node.type === 'url') || (node.type === 'link' && (!respectSilentFlag || !node.props.silent)); return (node.type === 'url') || (node.type === 'link' && (!respectSilentFlag || !node.props.silent));
}); }) as mfm.MfmUrl[];
const urls: string[] = unique(urlNodes.map(x => x.props.url)); const urls: string[] = unique(urlNodes.map(x => x.props.url));
return urls.reduce((array, url) => { return urls.reduce((array, url) => {