This commit is contained in:
syuilo 2023-02-22 15:28:17 +09:00
parent 3bb7afe544
commit 0fb9c372dd
22 changed files with 69 additions and 71 deletions

View file

@ -55,6 +55,7 @@ module.exports = {
'vue/multi-word-component-names': 'warn', 'vue/multi-word-component-names': 'warn',
'vue/require-v-for-key': 'warn', 'vue/require-v-for-key': 'warn',
'vue/no-unused-components': 'warn', 'vue/no-unused-components': 'warn',
'vue/no-unused-vars': 'warn',
'vue/valid-v-for': 'warn', 'vue/valid-v-for': 'warn',
'vue/return-in-computed-property': 'warn', 'vue/return-in-computed-property': 'warn',
'vue/no-setup-props-destructure': 'warn', 'vue/no-setup-props-destructure': 'warn',

View file

@ -43,7 +43,7 @@ const emit = defineEmits<{
}>(); }>();
const uiWindow = shallowRef<InstanceType<typeof MkWindow>>(); const uiWindow = shallowRef<InstanceType<typeof MkWindow>>();
const comment = ref(props.initialComment || ''); const comment = ref(props.initialComment ?? '');
function send() { function send() {
os.apiWithDialog('users/report-abuse', { os.apiWithDialog('users/report-abuse', {

View file

@ -209,7 +209,7 @@ function exec() {
} }
} else if (props.type === 'hashtag') { } else if (props.type === 'hashtag') {
if (!props.q || props.q === '') { if (!props.q || props.q === '') {
hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') || '[]'); hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]');
fetching.value = false; fetching.value = false;
} else { } else {
const cacheKey = `autocomplete:hashtag:${props.q}`; const cacheKey = `autocomplete:hashtag:${props.q}`;

View file

@ -69,7 +69,7 @@ const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown
if (loaded) { if (loaded) {
available.value = true; available.value = true;
} else { } else {
(document.getElementById(scriptId.value) || document.head.appendChild(Object.assign(document.createElement('script'), { (document.getElementById(scriptId.value) ?? document.head.appendChild(Object.assign(document.createElement('script'), {
async: true, async: true,
id: scriptId.value, id: scriptId.value,
src: src.value, src: src.value,

View file

@ -45,8 +45,8 @@ onMounted(() => {
src: media.url, src: media.url,
w: media.properties.width, w: media.properties.width,
h: media.properties.height, h: media.properties.height,
alt: media.comment || media.name, alt: media.comment ?? media.name,
comment: media.comment || media.name, comment: media.comment ?? media.name,
}; };
if (media.properties.orientation != null && media.properties.orientation >= 5) { if (media.properties.orientation != null && media.properties.orientation >= 5) {
[item.w, item.h] = [item.h, item.w]; [item.w, item.h] = [item.h, item.w];
@ -90,8 +90,8 @@ onMounted(() => {
[itemData.w, itemData.h] = [itemData.h, itemData.w]; [itemData.w, itemData.h] = [itemData.h, itemData.w];
} }
itemData.msrc = file.thumbnailUrl; itemData.msrc = file.thumbnailUrl;
itemData.alt = file.comment || file.name; itemData.alt = file.comment ?? file.name;
itemData.comment = file.comment || file.name; itemData.comment = file.comment ?? file.name;
itemData.thumbCropped = true; itemData.thumbCropped = true;
}); });

View file

@ -54,7 +54,7 @@ const props = withDefaults(defineProps<{
showGlobalToggle: true, showGlobalToggle: true,
}); });
let includingTypes = $computed(() => props.includingTypes || []); let includingTypes = $computed(() => props.includingTypes ?? []);
const dialog = $shallowRef<InstanceType<typeof MkModalWindow>>(); const dialog = $shallowRef<InstanceType<typeof MkModalWindow>>();

View file

@ -104,7 +104,7 @@ const {
enableInfiniteScroll, enableInfiniteScroll,
} = defaultStore.reactiveState; } = defaultStore.reactiveState;
const contentEl = $computed(() => props.pagination.pageEl || rootEl); const contentEl = $computed(() => props.pagination.pageEl ?? rootEl);
const scrollableElement = $computed(() => getScrollContainer(contentEl)); const scrollableElement = $computed(() => getScrollContainer(contentEl));
// //

View file

@ -154,7 +154,7 @@ let autocomplete = $ref(null);
let draghover = $ref(false); let draghover = $ref(false);
let quoteId = $ref(null); let quoteId = $ref(null);
let hasNotSpecifiedMentions = $ref(false); let hasNotSpecifiedMentions = $ref(false);
let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') || '[]')); let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
let imeText = $ref(''); let imeText = $ref('');
const draftKey = $computed((): string => { const draftKey = $computed((): string => {
@ -533,7 +533,7 @@ function onDrop(ev): void {
} }
function saveDraft() { function saveDraft() {
const draftData = JSON.parse(miLocalStorage.getItem('drafts') || '{}'); const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}');
draftData[draftKey] = { draftData[draftKey] = {
updatedAt: new Date(), updatedAt: new Date(),
@ -642,7 +642,7 @@ async function post(ev?: MouseEvent) {
emit('posted'); emit('posted');
if (postData.text && postData.text !== '') { if (postData.text && postData.text !== '') {
const hashtags_ = mfm.parse(postData.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag); const hashtags_ = mfm.parse(postData.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
const history = JSON.parse(miLocalStorage.getItem('hashtags') || '[]') as string[]; const history = JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]') as string[];
miLocalStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history)))); miLocalStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history))));
} }
posting = false; posting = false;
@ -746,7 +746,7 @@ onMounted(() => {
nextTick(() => { nextTick(() => {
// 稿 // 稿
if (!props.instant && !props.mention && !props.specified) { if (!props.instant && !props.mention && !props.specified) {
const draft = JSON.parse(miLocalStorage.getItem('drafts') || '{}')[draftKey]; const draft = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}')[draftKey];
if (draft) { if (draft) {
text = draft.data.text; text = draft.data.text;
useCw = draft.data.useCw; useCw = draft.data.useCw;

View file

@ -16,7 +16,7 @@
<template #label>{{ i18n.ts.username }}</template> <template #label>{{ i18n.ts.username }}</template>
<template #prefix>@</template> <template #prefix>@</template>
</MkInput> </MkInput>
<MkInput v-model="host" @update:model-value="search" :datalist="[hostname]"> <MkInput v-model="host" :datalist="[hostname]" @update:model-value="search">
<template #label>{{ i18n.ts.host }}</template> <template #label>{{ i18n.ts.host }}</template>
<template #prefix>@</template> <template #prefix>@</template>
</MkInput> </MkInput>

View file

@ -24,7 +24,7 @@ const rawUrl = computed(() => {
return props.url; return props.url;
} }
if (props.host == null && !customEmojiName.value.includes('@')) { if (props.host == null && !customEmojiName.value.includes('@')) {
return customEmojis.value.find(x => x.name === customEmojiName.value)?.url || null; return customEmojis.value.find(x => x.name === customEmojiName.value)?.url ?? null;
} }
return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
}); });
@ -32,7 +32,7 @@ const rawUrl = computed(() => {
const url = computed(() => const url = computed(() =>
defaultStore.reactiveState.disableShowingAnimatedImages.value && rawUrl.value defaultStore.reactiveState.disableShowingAnimatedImages.value && rawUrl.value
? getStaticImageUrl(rawUrl.value) ? getStaticImageUrl(rawUrl.value)
: rawUrl.value : rawUrl.value,
); );
const alt = computed(() => `:${customEmojiName.value}:`); const alt = computed(() => `:${customEmojiName.value}:`);

View file

@ -2,9 +2,9 @@
<div v-if="show" ref="el" :class="[$style.root]" :style="{ background: bg }"> <div v-if="show" ref="el" :class="[$style.root]" :style="{ background: bg }">
<div :class="[$style.upper, { [$style.slim]: narrow, [$style.thin]: thin_ }]"> <div :class="[$style.upper, { [$style.slim]: narrow, [$style.thin]: thin_ }]">
<div v-if="!thin_ && narrow && props.displayMyAvatar && $i" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu"> <div v-if="!thin_ && narrow && props.displayMyAvatar && $i" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu">
<MkAvatar :class="$style.avatar" :user="$i" /> <MkAvatar :class="$style.avatar" :user="$i"/>
</div> </div>
<div v-else-if="!thin_ && narrow && !hideTitle" :class="$style.buttonsLeft" /> <div v-else-if="!thin_ && narrow && !hideTitle" :class="$style.buttonsLeft"/>
<template v-if="metadata"> <template v-if="metadata">
<div v-if="!hideTitle" :class="$style.titleContainer" @click="top"> <div v-if="!hideTitle" :class="$style.titleContainer" @click="top">
@ -36,11 +36,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref, inject } from 'vue'; import { onMounted, onUnmounted, ref, inject } from 'vue';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import XTabs, { Tab } from './MkPageHeader.tabs.vue';
import { scrollToTop } from '@/scripts/scroll'; import { scrollToTop } from '@/scripts/scroll';
import { globalEvents } from '@/events'; import { globalEvents } from '@/events';
import { injectPageMetadata } from '@/scripts/page-metadata'; import { injectPageMetadata } from '@/scripts/page-metadata';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
import XTabs, { Tab } from './MkPageHeader.tabs.vue';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
tabs?: Tab[]; tabs?: Tab[];
@ -96,7 +96,7 @@ function onTabClick(): void {
} }
const calcBg = () => { const calcBg = () => {
const rawBg = metadata?.bg || 'var(--bg)'; const rawBg = metadata?.bg ?? 'var(--bg)';
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
tinyBg.setAlpha(0.85); tinyBg.setAlpha(0.85);
bg.value = tinyBg.toRgbString(); bg.value = tinyBg.toRgbString();

View file

@ -113,7 +113,7 @@ function onTabClick(tab: Tab, ev: MouseEvent): void {
} }
const calcBg = () => { const calcBg = () => {
const rawBg = metadata?.bg || 'var(--bg)'; const rawBg = metadata?.bg ?? 'var(--bg)';
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
tinyBg.setAlpha(0.85); tinyBg.setAlpha(0.85);
bg.value = tinyBg.toRgbString(); bg.value = tinyBg.toRgbString();

View file

@ -1,12 +1,12 @@
<template> <template>
<MkStickyContainer> <MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs" /></template> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :content-max="500"> <MkSpacer :content-max="500">
<div v-if="state == 'fetch-session-error'"> <div v-if="state == 'fetch-session-error'">
<p>{{ i18n.ts.somethingHappened }}</p> <p>{{ i18n.ts.somethingHappened }}</p>
</div> </div>
<div v-else-if="$i && !session"> <div v-else-if="$i && !session">
<MkLoading /> <MkLoading/>
</div> </div>
<div v-else-if="$i && session"> <div v-else-if="$i && session">
<XForm <XForm
@ -21,15 +21,16 @@
</div> </div>
<div v-if="state == 'accepted' && session"> <div v-if="state == 'accepted' && session">
<h1>{{ session.app.isAuthorized ? $t('already-authorized') : i18n.ts.allowed }}</h1> <h1>{{ session.app.isAuthorized ? $t('already-authorized') : i18n.ts.allowed }}</h1>
<p v-if="session.app.callbackUrl">{{ i18n.ts._auth.callback }} <p v-if="session.app.callbackUrl">
<MkEllipsis /> {{ i18n.ts._auth.callback }}
<MkEllipsis/>
</p> </p>
<p v-if="!session.app.callbackUrl">{{ i18n.ts._auth.pleaseGoBack }}</p> <p v-if="!session.app.callbackUrl">{{ i18n.ts._auth.pleaseGoBack }}</p>
</div> </div>
</div> </div>
<div v-else> <div v-else>
<p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p> <p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
<MkSignin @login="onLogin" /> <MkSignin @login="onLogin"/>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </MkStickyContainer>
@ -37,12 +38,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import { AuthSession } from 'misskey-js/built/entities';
import XForm from './auth.form.vue'; import XForm from './auth.form.vue';
import MkSignin from '@/components/MkSignin.vue'; import MkSignin from '@/components/MkSignin.vue';
import * as os from '@/os'; import * as os from '@/os';
import { $i, login } from '@/account'; import { $i, login } from '@/account';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import { AuthSession } from 'misskey-js/built/entities';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
const props = defineProps<{ const props = defineProps<{
@ -82,7 +83,7 @@ onMounted(async () => {
} else { } else {
state = 'waiting'; state = 'waiting';
} }
} catch (e) { } catch (err) {
state = 'fetch-session-error'; state = 'fetch-session-error';
} }
}); });

View file

@ -124,11 +124,11 @@ function saveFields() {
function save() { function save() {
os.apiWithDialog('i/update', { os.apiWithDialog('i/update', {
name: profile.name || null, name: profile.name ?? null,
description: profile.description || null, description: profile.description ?? null,
location: profile.location || null, location: profile.location ?? null,
birthday: profile.birthday || null, birthday: profile.birthday ?? null,
lang: profile.lang || null, lang: profile.lang ?? null,
isBot: !!profile.isBot, isBot: !!profile.isBot,
isCat: !!profile.isCat, isCat: !!profile.isCat,
showTimelineReplies: !!profile.showTimelineReplies, showTimelineReplies: !!profile.showTimelineReplies,

View file

@ -48,8 +48,8 @@ export class Storage<T extends StateDef> {
// 簡易的にキューイングして占有ロックとする // 簡易的にキューイングして占有ロックとする
private currentIdbJob: Promise<any> = Promise.resolve(); private currentIdbJob: Promise<any> = Promise.resolve();
private addIdbSetJob<T>(job: () => Promise<T>) { private addIdbSetJob<T>(job: () => Promise<T>) {
const promise = this.currentIdbJob.then(job, e => { const promise = this.currentIdbJob.then(job, err => {
console.error('Pizzax failed to save data to idb!', e); console.error('Pizzax failed to save data to idb!', err);
return job(); return job();
}); });
this.currentIdbJob = promise; this.currentIdbJob = promise;
@ -130,22 +130,22 @@ export class Storage<T extends StateDef> {
await defaultStore.ready; await defaultStore.ready;
api('i/registry/get-all', { scope: ['client', this.key] }) api('i/registry/get-all', { scope: ['client', this.key] })
.then(kvs => { .then(kvs => {
const cache: Partial<T> = {}; const cache: Partial<T> = {};
for (const [k, v] of Object.entries(this.def) as [keyof T, T[keyof T]['default']][]) { for (const [k, v] of Object.entries(this.def) as [keyof T, T[keyof T]['default']][]) {
if (v.where === 'account') { if (v.where === 'account') {
if (Object.prototype.hasOwnProperty.call(kvs, k)) { if (Object.prototype.hasOwnProperty.call(kvs, k)) {
this.reactiveState[k].value = this.state[k] = (kvs as Partial<T>)[k]; this.reactiveState[k].value = this.state[k] = (kvs as Partial<T>)[k];
cache[k] = (kvs as Partial<T>)[k]; cache[k] = (kvs as Partial<T>)[k];
} else { } else {
this.reactiveState[k].value = this.state[k] = v.default; this.reactiveState[k].value = this.state[k] = v.default;
}
} }
} }
}
return set(this.registryCacheKeyName, cache); return set(this.registryCacheKeyName, cache);
}) })
.then(() => resolve()); .then(() => resolve());
}, 1); }, 1);
} else { } else {
resolve(); resolve();

View file

@ -240,7 +240,7 @@ export function getNoteMenu(props: {
icon: 'ti ti-external-link', icon: 'ti ti-external-link',
text: i18n.ts.showOnRemote, text: i18n.ts.showOnRemote,
action: () => { action: () => {
window.open(appearNote.url || appearNote.uri, '_blank'); window.open(appearNote.url ?? appearNote.uri, '_blank');
}, },
} : undefined, } : undefined,
{ {
@ -302,7 +302,7 @@ export function getNoteMenu(props: {
icon: 'ti ti-exclamation-circle', icon: 'ti ti-exclamation-circle',
text: i18n.ts.reportAbuse, text: i18n.ts.reportAbuse,
action: () => { action: () => {
const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`; const u = appearNote.url ?? appearNote.uri ?? `${url}/notes/${appearNote.id}`;
os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
user: appearNote.user, user: appearNote.user,
initialComment: `Note: ${u}\n-----\n`, initialComment: `Note: ${u}\n-----\n`,
@ -344,7 +344,7 @@ export function getNoteMenu(props: {
icon: 'ti ti-external-link', icon: 'ti ti-external-link',
text: i18n.ts.showOnRemote, text: i18n.ts.showOnRemote,
action: () => { action: () => {
window.open(appearNote.url || appearNote.uri, '_blank'); window.open(appearNote.url ?? appearNote.uri, '_blank');
}, },
} : undefined] } : undefined]
.filter(x => x !== undefined); .filter(x => x !== undefined);

View file

@ -58,7 +58,7 @@ export class HpmlScope {
constructor(layerdStates: HpmlScope['layerdStates'], name?: HpmlScope['name']) { constructor(layerdStates: HpmlScope['layerdStates'], name?: HpmlScope['name']) {
this.layerdStates = layerdStates; this.layerdStates = layerdStates;
this.name = name || 'anonymous'; this.name = name ?? 'anonymous';
} }
@autobind @autobind

View file

@ -63,7 +63,7 @@ export class HpmlTypeChecker {
@autobind @autobind
public getExpectedType(v: Expr, slot: number): Type { public getExpectedType(v: Expr, slot: number): Type {
const def = funcDefs[v.type || '']; const def = funcDefs[v.type ?? ''];
if (def == null) { if (def == null) {
throw new Error('Unknown type: ' + v.type); throw new Error('Unknown type: ' + v.type);
} }
@ -107,7 +107,7 @@ export class HpmlTypeChecker {
return pageVar.type; return pageVar.type;
} }
const envVar = envVarsDef[v.value || '']; const envVar = envVarsDef[v.value ?? ''];
if (envVar !== undefined) { if (envVar !== undefined) {
return envVar; return envVar;
} }

View file

@ -10,7 +10,7 @@ export function getScrollContainer(el: HTMLElement | null): HTMLElement | null {
} }
} }
export function getStickyTop(el: HTMLElement, container: HTMLElement | null = null, top: number = 0) { export function getStickyTop(el: HTMLElement, container: HTMLElement | null = null, top = 0) {
if (!el.parentElement) return top; if (!el.parentElement) return top;
const data = el.dataset.stickyContainerHeaderHeight; const data = el.dataset.stickyContainerHeaderHeight;
const newTop = data ? Number(data) + top : top; const newTop = data ? Number(data) + top : top;
@ -23,14 +23,14 @@ export function getScrollPosition(el: HTMLElement | null): number {
return container == null ? window.scrollY : container.scrollTop; return container == null ? window.scrollY : container.scrollTop;
} }
export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance: number = 1, once: boolean = false) { export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) {
// とりあえず評価してみる // とりあえず評価してみる
if (isTopVisible(el)) { if (isTopVisible(el)) {
cb(); cb();
if (once) return null; if (once) return null;
} }
const container = getScrollContainer(el) || window; const container = getScrollContainer(el) ?? window;
const onScroll = ev => { const onScroll = ev => {
if (!document.body.contains(el)) return; if (!document.body.contains(el)) return;
@ -45,7 +45,7 @@ export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance: numbe
return removeListener; return removeListener;
} }
export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance: number = 1, once: boolean = false) { export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) {
const container = getScrollContainer(el); const container = getScrollContainer(el);
// とりあえず評価してみる // とりあえず評価してみる
@ -54,7 +54,7 @@ export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance: nu
if (once) return null; if (once) return null;
} }
const containerOrWindow = container || window; const containerOrWindow = container ?? window;
const onScroll = ev => { const onScroll = ev => {
if (!document.body.contains(el)) return; if (!document.body.contains(el)) return;
if (isBottomVisible(el, 1, container)) { if (isBottomVisible(el, 1, container)) {
@ -104,12 +104,12 @@ export function scrollToBottom(
} else { } else {
window.scroll({ window.scroll({
top: (el.scrollHeight - window.innerHeight + getStickyTop(el, container) + (window.innerWidth <= 500 ? 96 : 0)) || 0, top: (el.scrollHeight - window.innerHeight + getStickyTop(el, container) + (window.innerWidth <= 500 ? 96 : 0)) || 0,
...options ...options,
}); });
} }
} }
export function isTopVisible(el: HTMLElement, tolerance: number = 1): boolean { export function isTopVisible(el: HTMLElement, tolerance = 1): boolean {
const scrollTop = getScrollPosition(el); const scrollTop = getScrollPosition(el);
return scrollTop <= tolerance; return scrollTop <= tolerance;
} }
@ -124,6 +124,6 @@ export function getBodyScrollHeight() {
return Math.max( return Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight, document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight, document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight document.body.clientHeight, document.documentElement.clientHeight,
); );
} }

View file

@ -1,13 +1,13 @@
import { api } from '@/os';
import { $i } from '@/account';
import { Theme } from './scripts/theme'; import { Theme } from './scripts/theme';
import { miLocalStorage } from './local-storage'; import { miLocalStorage } from './local-storage';
import { api } from '@/os';
import { $i } from '@/account';
const lsCacheKey = $i ? `themes:${$i.id}` as const : null; const lsCacheKey = $i ? `themes:${$i.id}` as const : null;
export function getThemes(): Theme[] { export function getThemes(): Theme[] {
if ($i == null) return []; if ($i == null) return [];
return JSON.parse(miLocalStorage.getItem(lsCacheKey!) || '[]'); return JSON.parse(miLocalStorage.getItem(lsCacheKey!) ?? '[]');
} }
export async function fetchThemes(): Promise<void> { export async function fetchThemes(): Promise<void> {

View file

@ -125,7 +125,7 @@ function onAiClick(ev) {
if (window.innerWidth < 1024) { if (window.innerWidth < 1024) {
const currentUI = miLocalStorage.getItem('ui'); const currentUI = miLocalStorage.getItem('ui');
miLocalStorage.setItem('ui_temp', currentUI || 'default'); miLocalStorage.setItem('ui_temp', currentUI ?? 'default');
miLocalStorage.setItem('ui', 'default'); miLocalStorage.setItem('ui', 'default');
location.reload(); location.reload();
} }

View file

@ -1,7 +1,3 @@
export default function(user: { name?: string | null, username: string }): string { export default function(user: { name?: string | null, username: string }): string {
// Show username if name is empty. return user.name === '' ? user.username : user.name ?? user.username;
// XXX: typescript-eslint has no configuration to allow using `||` against string.
// https://github.com/typescript-eslint/typescript-eslint/issues/4906
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
return user.name || user.username;
} }