refactor (client): use ?? to check null/undefined

This commit is contained in:
naskya 2024-01-08 17:03:39 +09:00
parent be726a45f9
commit 1aec738200
Signed by: naskya
GPG key ID: 712D413B3A9FED5C
93 changed files with 267 additions and 267 deletions

View file

@ -55,7 +55,7 @@ export async function signout() {
export async function getAccounts(): Promise<
{ id: Account["id"]; token: Account["token"] }[]
> {
return (await get("accounts")) || [];
return (await get("accounts")) ?? [];
}
export async function addAccount(id: Account["id"], token: Account["token"]) {

View file

@ -59,7 +59,7 @@ const emit = defineEmits<{
}>();
const uiWindow = ref<InstanceType<typeof XWindow>>();
const comment = ref(props.initialComment || "");
const comment = ref(props.initialComment ?? "");
function send() {
os.apiWithDialog(

View file

@ -268,7 +268,7 @@ function exec() {
} else if (props.type === "hashtag") {
if (!props.q || props.q === "") {
hashtags.value = JSON.parse(
localStorage.getItem("hashtags") || "[]",
localStorage.getItem("hashtags") ?? "[]",
);
fetching.value = false;
} else {

View file

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

View file

@ -50,7 +50,7 @@ export default defineComponent({
const renderChildren = () =>
props.items.map((item, i) => {
if (!slots || !slots.default) return;
if (slots == null || slots.default == null) return;
const el = slots.default({
item,

View file

@ -65,8 +65,10 @@
v-model="inputValue"
autofocus
:autocomplete="input.autocomplete"
:type="input.type == 'search' ? 'search' : input.type || 'text'"
:placeholder="input.placeholder || undefined"
:type="
input.type === 'search' ? 'search' : input.type ?? 'text'
"
:placeholder="input.placeholder ?? undefined"
:style="{
width: input.type === 'search' ? '300px' : null,
}"
@ -294,7 +296,7 @@ const okButtonDisabled = computed<boolean>(() => {
if (props.input) {
if (props.input.minLength) {
if (
(inputValue.value || inputValue.value === "") &&
inputValue.value != null &&
(inputValue.value as string).length < props.input.minLength
) {
disabledReason.value = "charactersBelow";

View file

@ -185,7 +185,7 @@ function describe() {
},
{
done: (result) => {
if (!result || result.canceled) return;
if (result == null || result.canceled) return;
const comment = result.result;
os.api("drive/files/update", {
fileId: props.file.id,

View file

@ -363,7 +363,7 @@ function urlUpload() {
type: "url",
placeholder: i18n.ts.uploadFromUrlDescription,
}).then(({ canceled, result: url }) => {
if (canceled || !url) return;
if (canceled || url == null) return;
os.api("drive/files/upload-from-url", {
url,
folderId: folder.value ? folder.value.id : undefined,

View file

@ -106,7 +106,7 @@
.map((e) => ':' + e.name + ':')
"
@chosen="chosen"
>{{ category || i18n.ts.other }}</XSection
>{{ category ?? i18n.ts.other }}</XSection
>
</div>
<div v-once class="group">
@ -423,7 +423,7 @@ function reset() {
function getKey(
emoji: string | firefish.entities.CustomEmoji | UnicodeEmojiDef,
): string {
return typeof emoji === "string" ? emoji : emoji.emoji || `:${emoji.name}:`;
return typeof emoji === "string" ? emoji : emoji.emoji ?? `:${emoji.name}:`;
}
function chosen(emoji: any, ev?: MouseEvent) {
@ -450,7 +450,7 @@ function chosen(emoji: any, ev?: MouseEvent) {
}
function paste(event: ClipboardEvent) {
const paste = (event.clipboardData || window.clipboardData).getData("text");
const paste = (event.clipboardData ?? window.clipboardData).getData("text");
if (done(paste)) {
event.preventDefault();
}

View file

@ -9,7 +9,7 @@
</button>
<button
v-if="!hideFollowButton && isSignedIn && $i.id != user.id"
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
v-tooltip="full ? null : `${state} ${user.name ?? user.username}`"
class="kpoogebi _button follow-button"
:class="{
wait,
@ -19,7 +19,7 @@
blocking: isBlocking,
}"
:disabled="wait"
:aria-label="`${state} ${user.name || user.username}`"
:aria-label="`${state} ${user.name ?? user.username}`"
@click.stop="onClick"
>
<template v-if="!wait">
@ -141,7 +141,7 @@ async function onClick() {
const { canceled } = await os.confirm({
type: "warning",
text: i18n.t("unfollowConfirm", {
name: props.user.name || props.user.username,
name: props.user.name ?? props.user.username,
}),
});

View file

@ -25,11 +25,11 @@
v-if="form[item].type === 'number'"
v-model="values[item]"
type="number"
:step="form[item].step || 1"
:step="form[item].step ?? 1"
class="_formBlock"
>
<template #label
><span v-text="form[item].label || item"></span
><span v-text="form[item].label ?? item"></span
><span v-if="form[item].required === false">
({{ i18n.ts.optional }})</span
></template
@ -48,7 +48,7 @@
class="_formBlock"
>
<template #label
><span v-text="form[item].label || item"></span
><span v-text="form[item].label ?? item"></span
><span v-if="form[item].required === false">
({{ i18n.ts.optional }})</span
></template
@ -65,7 +65,7 @@
class="_formBlock"
>
<template #label
><span v-text="form[item].label || item"></span
><span v-text="form[item].label ?? item"></span
><span v-if="form[item].required === false">
({{ i18n.ts.optional }})</span
></template
@ -79,7 +79,7 @@
v-model="values[item]"
class="_formBlock"
>
<span v-text="form[item].label || item"></span>
<span v-text="form[item].label ?? item"></span>
<template v-if="form[item].description" #caption>{{
form[item].description
}}</template>
@ -90,7 +90,7 @@
class="_formBlock"
>
<template #label
><span v-text="form[item].label || item"></span
><span v-text="form[item].label ?? item"></span
><span v-if="form[item].required === false">
({{ i18n.ts.optional }})</span
></template
@ -109,7 +109,7 @@
class="_formBlock"
>
<template #label
><span v-text="form[item].label || item"></span
><span v-text="form[item].label ?? item"></span
><span v-if="form[item].required === false">
({{ i18n.ts.optional }})</span
></template
@ -132,7 +132,7 @@
class="_formBlock"
>
<template #label
><span v-text="form[item].label || item"></span
><span v-text="form[item].label ?? item"></span
><span v-if="form[item].required === false">
({{ i18n.ts.optional }})</span
></template
@ -146,7 +146,7 @@
class="_formBlock"
@click="form[item].action($event, values)"
>
<span v-text="form[item].content || item"></span>
<span v-text="form[item].content ?? item"></span>
</MkButton>
</template>
</div>

View file

@ -15,7 +15,7 @@
<span class="host">{{ instance.name ?? instance.host }}</span>
<span class="sub _monospace"
><b>{{ instance.host }}</b> /
{{ instance.softwareName || "?" }}
{{ instance.softwareName ?? "?" }}
{{ instance.softwareVersion }}</span
>
</div>

View file

@ -33,7 +33,7 @@ const ticker = ref<HTMLElement | null>(null);
// if no instance data is given, this is for the local instance
const instance = props.instance ?? {
faviconUrl: Instance.faviconUrl || Instance.iconUrl || "/favicon.ico",
faviconUrl: Instance.faviconUrl ?? Instance.iconUrl ?? "/favicon.ico",
name: instanceName,
themeColor: (
document.querySelector(

View file

@ -11,7 +11,7 @@
<span class="main">
<span class="username">@{{ username }}</span>
<span
v-if="host != localHost || defaultStore.state.showFullAcct"
v-if="host !== localHost || defaultStore.state.showFullAcct"
class="host"
>@{{ toUnicode(host) }}</span
>

View file

@ -21,7 +21,7 @@
<template v-for="item in items2">
<div v-if="item === null" class="divider"></div>
<span v-else-if="item.type === 'label'" class="label item">
<span :style="item.textStyle || ''">{{
<span :style="item.textStyle ?? ''">{{
item.text
}}</span>
</span>
@ -50,7 +50,7 @@
class="avatar"
disable-link
/>
<span :style="item.textStyle || ''">{{
<span :style="item.textStyle ?? ''">{{
item.text
}}</span>
<span
@ -76,7 +76,7 @@
v-if="item.icon"
:class="icon(`${item.icon} ph-fw`)"
></i>
<span :style="item.textStyle || ''">{{
<span :style="item.textStyle ?? ''">{{
item.text
}}</span>
<span
@ -121,7 +121,7 @@
v-model="item.ref"
:disabled="item.disabled"
class="form-switch"
:style="item.textStyle || ''"
:style="item.textStyle ?? ''"
>{{ item.text }}</FormSwitch
>
</span>
@ -136,7 +136,7 @@
v-if="item.icon"
:class="icon(`${item.icon} ph-fw`)"
></i>
<span :style="item.textStyle || ''">{{
<span :style="item.textStyle ?? ''">{{
item.text
}}</span>
<span class="caret"
@ -166,7 +166,7 @@
class="avatar"
disable-link
/>
<span :style="item.textStyle || ''">{{
<span :style="item.textStyle ?? ''">{{
item.text
}}</span>
<span

View file

@ -48,7 +48,7 @@ const color = accent.toRgbString();
function draw(): void {
const stats = props.src.slice().reverse();
const peak = Math.max.apply(null, stats) || 1;
const peak = Math.max(1, ...stats);
const _polylinePoints = stats.map((n, i) => [
i * (viewBoxX / (stats.length - 1)),

View file

@ -375,7 +375,7 @@ const isForeignLanguage: boolean =
defaultStore.state.detectPostLanguage &&
appearNote.value.text != null &&
(() => {
const targetLang = (translateLang || lang || navigator.language)?.slice(
const targetLang = (translateLang ?? lang ?? navigator.language)?.slice(
0,
2,
);
@ -395,7 +395,7 @@ async function translate() {
translating.value = true;
translation.value = await translate_(
appearNote.value.id,
translateLang || lang || navigator.language,
translateLang ?? lang ?? navigator.language,
);
// use UI language as the second translation language
@ -403,7 +403,7 @@ async function translate() {
translateLang != null &&
lang != null &&
translateLang !== lang &&
(!translation.value ||
(translation.value == null ||
translation.value.sourceLang.toLowerCase() ===
translateLang.slice(0, 2))
)

View file

@ -292,7 +292,7 @@ const isForeignLanguage: boolean =
defaultStore.state.detectPostLanguage &&
appearNote.value.text != null &&
(() => {
const targetLang = (translateLang || lang || navigator.language)?.slice(
const targetLang = (translateLang ?? lang ?? navigator.language)?.slice(
0,
2,
);
@ -312,7 +312,7 @@ async function translate() {
translating.value = true;
translation.value = await translate_(
appearNote.value.id,
translateLang || lang || navigator.language,
translateLang ?? lang ?? navigator.language,
);
// use UI language as the second translation language
@ -320,7 +320,7 @@ async function translate() {
translateLang != null &&
lang != null &&
translateLang !== lang &&
(!translation.value ||
(translation.value == null ||
translation.value.sourceLang.toLowerCase() ===
translateLang.slice(0, 2))
)

View file

@ -28,7 +28,7 @@
class="notes"
>
<XNote
:key="note._featuredId_ || note._prId_ || note.id"
:key="note._featuredId_ ?? note._prId_ ?? note.id"
class="qtqtichx"
:note="note"
/>

View file

@ -64,7 +64,7 @@ const props = withDefaults(
},
);
const includingTypes = computed(() => props.includingTypes || []);
const includingTypes = computed(() => props.includingTypes ?? []);
const dialog = ref<InstanceType<typeof XModalWindow>>();

View file

@ -181,7 +181,7 @@ onMounted(() => {
}
for (
let i = 0;
i < (pagingComponent.value.items || []).length;
i < (pagingComponent.value.items ?? []).length;
i++
) {
if (

View file

@ -18,7 +18,7 @@ const tweened = reactive({
watch(
() => props.value,
(n) => {
gsap.to(tweened, { duration: 0.6, number: Number(n) || 0 });
gsap.to(tweened, { duration: 0.6, number: Number(n) ?? 0 });
},
{
immediate: true,

View file

@ -151,8 +151,8 @@ const init = async (): Promise<void> => {
.api(props.pagination.endpoint, {
...params,
limit: props.pagination.noPaging
? props.pagination.limit || 10
: (props.pagination.limit || 10) + 1,
? props.pagination.limit ?? 10
: (props.pagination.limit ?? 10) + 1,
})
.then(
(res) => {

View file

@ -389,7 +389,7 @@ const draghover = ref(false);
const quoteId = ref(null);
const hasNotSpecifiedMentions = ref(false);
const recentHashtags = ref(
JSON.parse(localStorage.getItem("hashtags") || "[]"),
JSON.parse(localStorage.getItem("hashtags") ?? "[]"),
);
const imeText = ref("");
@ -460,10 +460,10 @@ const canPost = computed((): boolean => {
!posting.value &&
(textLength.value >= 1 ||
files.value.length >= 1 ||
!!poll.value ||
!!props.renote) &&
poll.value != null ||
props.renote != null) &&
textLength.value <= maxTextLength.value &&
(!poll.value || poll.value.choices.length >= 2)
(poll.value == null || poll.value.choices.length >= 2)
);
});
@ -970,7 +970,7 @@ function onDrop(ev): void {
}
function saveDraft() {
const draftData = JSON.parse(localStorage.getItem("drafts") || "{}");
const draftData = JSON.parse(localStorage.getItem("drafts") ?? "{}");
draftData[draftKey.value] = {
updatedAt: new Date(),
@ -990,7 +990,7 @@ function saveDraft() {
}
function deleteDraft() {
const draftData = JSON.parse(localStorage.getItem("drafts") || "{}");
const draftData = JSON.parse(localStorage.getItem("drafts") ?? "{}");
delete draftData[draftKey.value];
@ -1013,7 +1013,7 @@ async function post() {
: undefined,
channelId: props.channel ? props.channel.id : undefined,
poll: poll.value,
cw: useCw.value ? cw.value || "" : undefined,
cw: useCw.value ? cw.value ?? "" : undefined,
lang: language.value ? language.value : undefined,
localOnly: localOnly.value,
visibility:
@ -1065,7 +1065,7 @@ async function post() {
.filter((x) => x.type === "hashtag")
.map((x) => x.props.hashtag);
const history = JSON.parse(
localStorage.getItem("hashtags") || "[]",
localStorage.getItem("hashtags") ?? "[]",
) as string[];
localStorage.setItem(
"hashtags",
@ -1184,7 +1184,7 @@ onMounted(() => {
autosize(textareaEl.value);
// 稿
if (!props.instant && !props.mention && !props.specified) {
const draft = JSON.parse(localStorage.getItem("drafts") || "{}")[
const draft = JSON.parse(localStorage.getItem("drafts") ?? "{}")[
draftKey.value
];
if (draft) {
@ -1194,7 +1194,7 @@ onMounted(() => {
visibility.value = draft.data.visibility;
localOnly.value = draft.data.localOnly;
language.value = draft.data.lang;
files.value = (draft.data.files || []).filter(
files.value = (draft.data.files ?? []).filter(
(draftFile) => draftFile,
);
if (draft.data.poll) {

View file

@ -105,7 +105,7 @@ async function describe(file) {
},
{
done: (result) => {
if (!result || result.canceled) return;
if (result == null || result.canceled) return;
const comment =
result.result.length === 0 ? null : result.result;
os.api("drive/files/update", {

View file

@ -1,7 +1,7 @@
<template>
<MkEmoji
:emoji="reaction"
:custom-emojis="customEmojis || []"
:custom-emojis="customEmojis ?? []"
:is-reaction="true"
:normal="true"
:no-style="noStyle"

View file

@ -33,7 +33,7 @@
<template #suffix>@{{ host }}</template>
</MkInput>
<MkInput
v-if="!user || (user && !user.usePasswordLessLogin)"
v-if="user == null || (user && !user.usePasswordLessLogin)"
v-model="password"
class="_formBlock"
:placeholder="i18n.ts.password"

View file

@ -310,12 +310,12 @@ const host = toUnicode(config.host);
const hcaptcha = ref();
const recaptcha = ref();
const username: string = ref("");
const password: string = ref("");
const retypedPassword: string = ref("");
const invitationCode: string = ref("");
const username = ref("");
const password = ref("");
const retypedPassword = ref("");
const invitationCode = ref("");
const email = ref("");
const usernameState:
const usernameState = ref<
| null
| "wait"
| "ok"
@ -323,9 +323,10 @@ const usernameState:
| "error"
| "invalid-format"
| "min-range"
| "max-range" = ref(null);
const invitationState: null | "entered" = ref(null);
const emailState:
| "max-range"
>(null);
const invitationState = ref<null | "entered">(null);
const emailState = ref<
| null
| "wait"
| "ok"
@ -335,11 +336,12 @@ const emailState:
| "unavailable:mx"
| "unavailable:smtp"
| "unavailable"
| "error" = ref(null);
const passwordStrength: "" | "low" | "medium" | "high" = ref("");
const passwordRetypeState: null | "match" | "not-match" = ref(null);
const submitting: boolean = ref(false);
const ToSAgreement: boolean = ref(false);
| "error"
>(null);
const passwordStrength = ref<"" | "low" | "medium" | "high">("");
const passwordRetypeState = ref<null | "match" | "not-match">(null);
const submitting = ref(false);
const ToSAgreement = ref(false);
const hCaptchaResponse = ref(null);
const reCaptchaResponse = ref(null);

View file

@ -11,7 +11,7 @@
@closed="$emit('closed')"
@ok="ok()"
>
<template #header>{{ title || i18n.ts.generateAccessToken }}</template>
<template #header>{{ title ?? i18n.ts.generateAccessToken }}</template>
<div v-if="information" class="_section">
<MkInfo warn>{{ information }}</MkInfo>
</div>
@ -32,7 +32,7 @@
i18n.ts.enableAll
}}</MkButton>
<MkSwitch
v-for="kind in initialPermissions || kinds"
v-for="kind in initialPermissions ?? kinds"
:key="kind"
v-model="permissions[kind]"
style="margin-bottom: 6px"

View file

@ -242,7 +242,7 @@ const dialog = ref<InstanceType<typeof XModalWindow>>();
const tutorial = computed({
get() {
return defaultStore.reactiveState.tutorial.value || 0;
return defaultStore.reactiveState.tutorial.value ?? 0;
},
set(value) {
defaultStore.set("tutorial", value);

View file

@ -13,7 +13,7 @@
:target="target"
:title="url"
:class="{
hasButton: tweetId || player.url,
hasButton: tweetId ?? player.url,
}"
>
<div v-if="thumbnail" class="thumbnail">
@ -51,10 +51,10 @@
<MkLoading mini />
</div>
<div v-else>
<h3 :title="title || undefined">{{ title || url }}</h3>
<p :title="description">
<h3 :title="title ?? undefined">{{ title ?? url }}</h3>
<p :title="description ?? undefined">
<span>
<span :title="sitename || undefined">
<span :title="sitename ?? undefined">
<img v-if="icon" class="icon" :src="icon" />
{{ sitename }}
</span>
@ -72,7 +72,7 @@
: '?autoplay=1&auto_play=1')
"
:style="`aspect-ratio: ${
(player.width || 1) / (player.height || 1)
(player.width ?? 1) / (player.height ?? 1)
}`"
frameborder="0"
allow="autoplay; encrypted-media"
@ -153,7 +153,7 @@ if (
requestUrl.hostname = "www.youtube.com";
}
const requestLang = (lang || "ja-JP").replace("ja-KS", "ja-JP");
const requestLang = (lang ?? "ja-JP").replace("ja-KS", "ja-JP");
requestUrl.hash = "";

View file

@ -4,7 +4,7 @@
<span
v-if="user.host || detail || defaultStore.state.showFullAcct"
class="host"
>@{{ user.host || host }}</span
>@{{ user.host ?? host }}</span
>
</span>
</template>

View file

@ -2,7 +2,7 @@
<Mfm
v-if="show"
:class="$style.root"
:text="user.name || user.username"
:text="user.name ?? user.username"
:plain="true"
:nowrap="nowrap"
:custom-emojis="user.emojis"

View file

@ -113,31 +113,31 @@ export default defineComponent({
let style: string;
switch (token.props.name) {
case "tada": {
const speed = validTime(token.props.args.speed) || "1s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
// const ease = validEase(token.props.args.ease) || "linear";
const speed = validTime(token.props.args.speed) ?? "1s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
// const ease = validEase(token.props.args.ease) ?? "linear";
style = `font-size: 150%; animation: tada ${speed} ${delay} linear ${loop} both;`;
break;
}
case "jelly": {
const speed = validTime(token.props.args.speed) || "1s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "1s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-rubberBand ${speed} ${delay} linear ${loop} both;`;
break;
}
case "twitch": {
const speed = validTime(token.props.args.speed) || "0.5s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "0.5s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-twitch ${speed} ${delay} ease ${loop};`;
break;
}
case "shake": {
const speed = validTime(token.props.args.speed) || "0.5s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "0.5s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-shake ${speed} ${delay} ease ${loop};`;
break;
}
@ -152,30 +152,30 @@ export default defineComponent({
: token.props.args.y
? "mfm-spinY"
: "mfm-spin";
const speed = validTime(token.props.args.speed) || "1.5s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "1.5s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: ${anime} ${speed} ${delay} linear ${loop}; animation-direction: ${direction};`;
break;
}
case "jump": {
const speed = validTime(token.props.args.speed) || "0.75s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "0.75s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-jump ${speed} ${delay} linear ${loop};`;
break;
}
case "bounce": {
const speed = validTime(token.props.args.speed) || "0.75s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "0.75s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-bounce ${speed} ${delay} linear ${loop}; transform-origin: center bottom;`;
break;
}
case "rainbow": {
const speed = validTime(token.props.args.speed) || "1s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "1s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-rainbow ${speed} ${delay} linear ${loop};`;
break;
}
@ -189,9 +189,9 @@ export default defineComponent({
const direction = token.props.args.out
? "alternate-reverse"
: "alternate";
const speed = validTime(token.props.args.speed) || "1.5s";
const delay = validTime(token.props.args.delay) || "0s";
const loop = validNumber(token.props.args.loop) || "infinite";
const speed = validTime(token.props.args.speed) ?? "1.5s";
const delay = validTime(token.props.args.delay) ?? "0s";
const loop = validNumber(token.props.args.loop) ?? "infinite";
style = `animation: mfm-fade ${speed} ${delay} linear ${loop}; animation-direction: ${direction};`;
break;
}
@ -395,7 +395,7 @@ export default defineComponent({
this.author &&
this.author.host != null
? this.author.host
: token.props.host) || host,
: token.props.host) ?? host,
username: token.props.username,
}),
];

View file

@ -35,7 +35,7 @@ export default defineComponent({
function click() {
props.hpml.updatePageVar(
props.block.name,
value.value + (props.block.inc || 1),
value.value + (props.block.inc ?? 1),
);
props.hpml.eval();
}

View file

@ -58,7 +58,7 @@ function calc(el: Element) {
const info = mountings.get(el);
const width = el.clientWidth;
if (!info || info.previousWidth === width) return;
if (info == null || info.previousWidth === width) return;
// アクティベート前などでsrcが描画されていない場合
if (!width) {

View file

@ -7,7 +7,7 @@ export const acct = (user: firefish.Acct) => {
};
export const userName = (user: firefish.entities.User) => {
return user.name || user.username;
return user.name ?? user.username;
};
export const userPage = (user: firefish.Acct, path?, absolute = false) => {

View file

@ -123,7 +123,7 @@ function checkForSplash() {
// #region Set lang attr
const html = document.documentElement;
html.setAttribute("lang", lang || "en-US");
html.setAttribute("lang", lang ?? "en-US");
html.setAttribute("dir", langmap[lang].rtl === true ? "rtl" : "ltr");
//#endregion
@ -134,7 +134,7 @@ function checkForSplash() {
if (loginId) {
const target = getUrlWithoutLoginId(location.href);
if (!$i || $i.id !== loginId) {
if ($i == null || $i.id !== loginId) {
const account = await getAccountFromId(loginId);
if (account) {
await login(account.token, target);
@ -437,7 +437,7 @@ function checkForSplash() {
if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) {
toast(
i18n.t("welcomeBackWithName", {
name: $i.name || $i.username,
name: $i.name ?? $i.username,
}),
);
}

View file

@ -314,7 +314,7 @@ export function confirm(props: {
},
{
done: (result) => {
resolve(result || { canceled: true });
resolve(result ?? { canceled: true });
},
},
"closed",
@ -342,7 +342,7 @@ export function yesno(props: {
},
{
done: (result) => {
resolve(result || { canceled: true });
resolve(result ?? { canceled: true });
},
},
"closed",
@ -383,7 +383,7 @@ export function inputText(props: {
},
{
done: (result) => {
resolve(result || { canceled: true });
resolve(result ?? { canceled: true });
},
},
"closed",
@ -421,7 +421,7 @@ export function inputParagraph(props: {
},
{
done: (result) => {
resolve(result || { canceled: true });
resolve(result ?? { canceled: true });
},
},
"closed",
@ -461,7 +461,7 @@ export function inputNumber(props: {
},
{
done: (result) => {
resolve(result || { canceled: true });
resolve(result ?? { canceled: true });
},
},
"closed",
@ -553,7 +553,7 @@ export function select<C = any>(
},
{
done: (result) => {
resolve(result || { canceled: true });
resolve(result ?? { canceled: true });
},
},
"closed",

View file

@ -31,7 +31,7 @@
:key="category"
class="emojis"
>
<template #header>{{ category || i18n.ts.other }}</template>
<template #header>{{ category ?? i18n.ts.other }}</template>
<div class="zuvgdzyt">
<XEmoji
v-for="emoji in customEmojis.filter(

View file

@ -41,7 +41,7 @@
@click="easterEgg"
/>
<div class="name">
<b>{{ $instance.name || host }}</b>
<b>{{ $instance.name ?? host }}</b>
</div>
</div>
</div>
@ -99,7 +99,7 @@
></template>
{{
i18n.t("_aboutFirefish.donateHost", {
host: $instance.name || host,
host: $instance.name ?? host,
})
}}
<template #suffix>Donate</template>
@ -209,7 +209,7 @@ withDefaults(
const stats = ref(null);
const instanceIcon = ref<HTMLImageElement>();
let iconClicks = 0;
const iconSrc = ref(instance.iconUrl || instance.faviconUrl || "/favicon.ico");
const iconSrc = ref(instance.faviconUrl ?? instance.iconUrl ?? "/favicon.ico");
const instanceIconAnimation = ref("");
const tabs = ["overview", "emojis", "charts"];
const tab = ref(tabs[0]);
@ -276,8 +276,8 @@ function easterEgg() {
setTimeout(() => {
if (iconClicks % 6 === 0) {
iconSrc.value =
instance.iconUrl ||
instance.faviconUrl ||
instance.faviconUrl ??
instance.iconUrl ??
"/favicon.ico";
} else {
iconSrc.value = "/static-assets/woozy.png";

View file

@ -148,7 +148,7 @@ function onTabClick(tab: Tab, ev: MouseEvent): void {
}
const calcBg = () => {
const rawBg = metadata?.bg || "var(--bg)";
const rawBg = metadata?.bg ?? "var(--bg)";
const tinyBg = tinycolor(
rawBg.startsWith("var(")
? getComputedStyle(document.documentElement).getPropertyValue(

View file

@ -32,7 +32,7 @@
<MkCaptcha
provider="hcaptcha"
:sitekey="
hcaptchaSiteKey ||
hcaptchaSiteKey ??
'10000000-ffff-ffff-ffff-000000000001'
"
/>

View file

@ -47,7 +47,7 @@ async function init() {
function save() {
os.apiWithDialog("admin/update-meta", {
hiddenTags:
hiddenTags.value.split("\n").map((h: string) => h.trim()) || [],
hiddenTags.value.split("\n").map((h: string) => h.trim()) ?? [],
}).then(() => {
fetchInstance();
});

View file

@ -5,7 +5,11 @@
<div class="lxpfedzu">
<div class="banner">
<img
:src="$instance.iconUrl || '/favicon.ico'"
:src="
$instance.faviconUrl ??
$instance.iconUrl ??
'/favicon.ico'
"
alt=""
class="icon"
/>

View file

@ -69,9 +69,9 @@ async function init() {
function save() {
os.apiWithDialog("admin/update-meta", {
blockedHosts: blockedHosts.value.split("\n").map((h) => h.trim()) || [],
blockedHosts: blockedHosts.value.split("\n").map((h) => h.trim()) ?? [],
silencedHosts:
silencedHosts.value.split("\n").map((h) => h.trim()) || [],
silencedHosts.value.split("\n").map((h) => h.trim()) ?? [],
}).then(() => {
fetchInstance();
});

View file

@ -66,7 +66,7 @@ async function addRelay() {
.catch((err: any) => {
os.alert({
type: "error",
text: err.message || err,
text: err.message ?? err,
});
});
}
@ -81,7 +81,7 @@ function remove(inbox: string) {
.catch((err: any) => {
os.alert({
type: "error",
text: err.message || err,
text: err.message ?? err,
});
});
}

View file

@ -126,7 +126,7 @@ const accepted = () => {
} else {
location.href = `${session.value.app.callbackUrl}?token=${
session.value.token
}&code=${session.value.token}&state=${getUrlParams().state || ""}`;
}&code=${session.value.token}&state=${getUrlParams().state ?? ""}`;
}
}
};

View file

@ -41,7 +41,7 @@ function menu(ev) {
(res) => {
os.alert({
type: "info",
text: `${res.license || i18n.ts.notSet}`,
text: `${res.license ?? i18n.ts.notSet}`,
});
},
);

View file

@ -11,7 +11,7 @@ import { i18n } from "@/i18n";
async function follow(user): Promise<void> {
const { canceled } = await os.confirm({
type: "question",
text: i18n.t("followConfirm", { name: user.name || user.username }),
text: i18n.t("followConfirm", { name: user.name ?? user.username }),
});
if (canceled) {

View file

@ -105,7 +105,7 @@
<MkAcct :user="post.user" />
</div>
<MkFollowButton
v-if="!$i || $i.id != post.user.id"
v-if="!isSignedIn || $i.id !== post.user.id"
:user="post.user"
:inline="true"
:transparent="false"
@ -163,7 +163,7 @@ import { definePageMetadata } from "@/scripts/page-metadata";
import { shareAvailable } from "@/scripts/share-available";
import { defaultStore } from "@/store";
import icon from "@/scripts/icon";
import { isSignedIn } from "@/reactiveAccount";
import { $i, isSignedIn } from "@/reactiveAccount";
const router = useRouter();

View file

@ -33,7 +33,7 @@
<div class="fnfelxur">
<img :src="faviconUrl" alt="" class="icon" />
<span class="name">{{
instance.name || `(${i18n.ts.unknown})`
instance.name ?? `(${i18n.ts.unknown})`
}}</span>
</div>
<MkKeyValue :copy="host" oneline style="margin: 1em 0">
@ -51,12 +51,12 @@
<template #value
><span class="_monospace"
>{{
instance.softwareName ||
instance.softwareName ??
`(${i18n.ts.unknown})`
}}
/
{{
instance.softwareVersion ||
instance.softwareVersion ??
`(${i18n.ts.unknown})`
}}</span
></template
@ -68,11 +68,11 @@
}}</template>
<template #value
>{{
instance.maintainerName ||
instance.maintainerName ??
`(${i18n.ts.unknown})`
}}
({{
instance.maintainerEmail ||
instance.maintainerEmail ??
`(${i18n.ts.unknown})`
}})</template
>

View file

@ -238,7 +238,7 @@ function clear() {
}
function saveDraft() {
const drafts = JSON.parse(localStorage.getItem("message_drafts") || "{}");
const drafts = JSON.parse(localStorage.getItem("message_drafts") ?? "{}");
drafts[draftKey.value] = {
updatedAt: new Date(),
@ -252,7 +252,7 @@ function saveDraft() {
}
function deleteDraft() {
const drafts = JSON.parse(localStorage.getItem("message_drafts") || "{}");
const drafts = JSON.parse(localStorage.getItem("message_drafts") ?? "{}");
delete drafts[draftKey.value];
@ -270,7 +270,7 @@ onMounted(() => {
new Autocomplete(textEl.value, text);
// 稿
const draft = JSON.parse(localStorage.getItem("message_drafts") || "{}")[
const draft = JSON.parse(localStorage.getItem("message_drafts") ?? "{}")[
draftKey.value
];
if (draft) {

View file

@ -11,7 +11,7 @@
<MkPagination
v-if="pagination"
ref="pagingComponent"
:key="userAcct || groupId"
:key="userAcct ?? groupId"
:pagination="pagination"
>
<template #empty>
@ -162,7 +162,7 @@ async function fetch() {
const acct = Acct.parse(props.userAcct);
user.value = await os.api("users/show", {
username: acct.username,
host: acct.host || undefined,
host: acct.host ?? undefined,
});
group.value = null;

View file

@ -181,7 +181,7 @@ definePageMetadata(
? ""
: i18n.t("noteOf", {
user:
appearNote.value.user.name ||
appearNote.value.user.name ??
appearNote.value.user.username,
}),
subtitle: new Date(
@ -192,7 +192,7 @@ definePageMetadata(
share: {
title: i18n.t("noteOf", {
user:
appearNote.value.user.name ||
appearNote.value.user.name ??
appearNote.value.user.username,
}),
text: appearNote.value.text,

View file

@ -150,7 +150,7 @@
<MkAcct :user="page.user" />
</div>
<MkFollowButton
v-if="!$i || $i.id != page.user.id"
v-if="!isSignedIn || $i.id !== page.user.id"
:user="page.user"
:inline="true"
:transparent="false"
@ -215,7 +215,7 @@ import { definePageMetadata } from "@/scripts/page-metadata";
import { shareAvailable } from "@/scripts/share-available";
import { defaultStore } from "@/store";
import icon from "@/scripts/icon";
import { isSignedIn } from "@/reactiveAccount";
import { $i, isSignedIn } from "@/reactiveAccount";
const props = defineProps<{
pageName: string;
@ -272,7 +272,7 @@ function share() {
function shareWithNote() {
os.post({
initialText: `${page.value.title || page.value.name} ${url}/@${
initialText: `${page.value.title ?? page.value.name} ${url}/@${
page.value.user.username
}/pages/${page.value.name}`,
});
@ -312,11 +312,11 @@ definePageMetadata(
computed(() =>
page.value
? {
title: computed(() => page.value.title || page.value.name),
title: computed(() => page.value.title ?? page.value.name),
avatar: page.value.user,
path: `/@${page.value.user.username}/pages/${page.value.name}`,
share: {
title: page.value.title || page.value.name,
title: page.value.title ?? page.value.name,
text: page.value.summary,
},
}

View file

@ -66,7 +66,7 @@ const pushRegistrationInServer = computed(
() => allowButton.value?.pushRegistrationInServer,
);
const sendReadMessage = computed(
() => pushRegistrationInServer.value?.sendReadMessage || false,
() => pushRegistrationInServer.value?.sendReadMessage ?? false,
);
async function readAllUnreadNotes() {

View file

@ -169,7 +169,7 @@ const connection = isSignedIn && stream.useChannel("main");
const profiles = ref<Record<string, Profile> | null>(null);
os.api("i/registry/get-all", { scope }).then((res) => {
profiles.value = res || {};
profiles.value = res ?? {};
});
function isObject(value: unknown): value is Record<string, unknown> {

View file

@ -21,7 +21,7 @@
>
{{ i18n.t("_sfx." + type) }}
<template #suffix>{{
sounds[type].type || i18n.ts.none
sounds[type].type ?? i18n.ts.none
}}</template>
<template #suffixIcon
><i :class="icon('ph-caret-down')"></i

View file

@ -37,7 +37,7 @@
:style="{ color: 'var(--error)' }"
></i>
</template>
{{ webhook.name || webhook.url }}
{{ webhook.name ?? webhook.url }}
<template #suffix>
<MkTime
v-if="webhook.latestSentAt"

View file

@ -108,7 +108,7 @@
v-if="
patrons?.includes(
`@${user.username}@${
user.host || host
user.host ?? host
}`,
)
"
@ -197,7 +197,7 @@
v-if="
patrons?.includes(
`@${user.username}@${
user.host || host
user.host ?? host
}`,
)
"

View file

@ -17,8 +17,8 @@
<div class="main">
<img
:src="
instance.iconUrl ||
instance.faviconUrl ||
instance.faviconUrl ??
instance.iconUrl ??
'/favicon.ico'
"
alt=""
@ -41,7 +41,7 @@
<div
class="desc"
v-html="
meta.description || i18n.ts.headlineFirefish
meta.description ?? i18n.ts.headlineFirefish
"
></div>
</div>

View file

@ -15,7 +15,7 @@
<div class="about">
<div
class="desc"
v-html="meta.description || i18n.ts.headlineFirefish"
v-html="meta.description ?? i18n.ts.headlineFirefish"
></div>
</div>
<div class="action">

View file

@ -30,7 +30,7 @@
<div
class="desc"
v-html="
meta.description || i18n.ts.headlineFirefish
meta.description ?? i18n.ts.headlineFirefish
"
></div>
</div>

View file

@ -41,16 +41,16 @@ export class Storage<T extends StateDef> {
// TODO: indexedDBにする
const deviceState = JSON.parse(
localStorage.getItem(this.keyForLocalStorage) || "{}",
localStorage.getItem(this.keyForLocalStorage) ?? "{}",
);
const deviceAccountState = isSignedIn
? JSON.parse(
localStorage.getItem(`${this.keyForLocalStorage}::${$i.id}`) || "{}",
localStorage.getItem(`${this.keyForLocalStorage}::${$i.id}`) ?? "{}",
)
: {};
const registryCache = isSignedIn
? JSON.parse(
localStorage.getItem(`${this.keyForLocalStorage}::cache::${$i.id}`) ||
localStorage.getItem(`${this.keyForLocalStorage}::cache::${$i.id}`) ??
"{}",
)
: {};
@ -136,7 +136,7 @@ export class Storage<T extends StateDef> {
const cache = JSON.parse(
localStorage.getItem(
`${this.keyForLocalStorage}::cache::${$i.id}`,
) || "{}",
) ?? "{}",
);
if (cache[key] !== value) {
cache[key] = value;
@ -159,7 +159,7 @@ export class Storage<T extends StateDef> {
switch (this.def[key].where) {
case "device": {
const deviceState = JSON.parse(
localStorage.getItem(this.keyForLocalStorage) || "{}",
localStorage.getItem(this.keyForLocalStorage) ?? "{}",
);
deviceState[key] = value;
localStorage.setItem(
@ -171,7 +171,7 @@ export class Storage<T extends StateDef> {
case "deviceAccount": {
if (!isSignedIn) break;
const deviceAccountState = JSON.parse(
localStorage.getItem(`${this.keyForLocalStorage}::${$i.id}`) || "{}",
localStorage.getItem(`${this.keyForLocalStorage}::${$i.id}`) ?? "{}",
);
deviceAccountState[key] = value;
localStorage.setItem(
@ -183,7 +183,7 @@ export class Storage<T extends StateDef> {
case "account": {
if (!isSignedIn) break;
const cache = JSON.parse(
localStorage.getItem(`${this.keyForLocalStorage}::cache::${$i.id}`) ||
localStorage.getItem(`${this.keyForLocalStorage}::cache::${$i.id}`) ??
"{}",
);
cache[key] = value;

View file

@ -143,7 +143,7 @@ function registerPostFormAction({ pluginId, title, handler }) {
pluginContext.execFn(handler, [
utils.jsToVal(form),
values.FN_NATIVE(([key, value]) => {
if (!key || !value) {
if (key == null || value == null) {
return;
}
update(utils.valToJs(key), utils.valToJs(value));

View file

@ -9,6 +9,6 @@ export const $i = accountData
: null;
export const isSignedIn = $i != null;
export const isModerator = isSignedIn && ($i.isModerator || $i.isAdmin);
export const isAdmin = isSignedIn && $i.isAdmin;
export const isEmojiMod = isSignedIn && $i.emojiModPerm !== "unauthorized";
export const isModerator = $i != null && ($i.isModerator || $i.isAdmin);
export const isAdmin = $i?.isAdmin;
export const isEmojiMod = $i != null && $i?.emojiModPerm !== "unauthorized";

View file

@ -34,7 +34,7 @@ export function createAiScriptEnv(opts) {
const res = await os.api(
ep.value,
utils.valToJs(param),
token ? token.value : opts.token || null,
token ? token.value : opts.token ?? null,
);
return utils.jsToVal(res);
}),

View file

@ -15,7 +15,7 @@ function checkLangMute(
const mutedLangList = new Set(mutedLangs.flatMap((e) => e));
// handle subtags
// e.g. if lang = "zh-hant-tw", check ["zh", "zh-hant", "zh-hant-tw"]
const langChunks: string[] = (note.lang || "").split("-");
const langChunks: string[] = (note.lang ?? "").split("-");
for (let i = 0; i < langChunks.length; i++) {
const lang = langChunks.slice(0, i + 1).join("-");
if (mutedLangList.has(lang)) {

View file

@ -12,7 +12,7 @@ ChiptuneJsConfig.prototype.constructor = ChiptuneJsConfig;
export function ChiptuneJsPlayer(config: object) {
this.libopenmpt = null;
this.config = config;
this.audioContext = config.context || new ChiptuneAudioContext();
this.audioContext = config.context ?? new ChiptuneAudioContext();
this.context = this.audioContext.createGain();
this.currentPlayingNode = null;
this.handlers = [];
@ -157,7 +157,7 @@ ChiptuneJsPlayer.prototype.play = async function (buffer: ArrayBuffer) {
}
this.libopenmpt._openmpt_module_set_repeat_count(
processNode.modulePtr,
this.config.repeatCount || 0,
this.config.repeatCount ?? 0,
);
this.currentPlayingNode = processNode;
processNode.connect(this.context);

View file

@ -6,19 +6,19 @@ export function collectPageVars(content) {
pageVars.push({
name: x.name,
type: "string",
value: x.default || "",
value: x.default ?? "",
});
} else if (x.type === "textareaInput") {
pageVars.push({
name: x.name,
type: "string",
value: x.default || "",
value: x.default ?? "",
});
} else if (x.type === "numberInput") {
pageVars.push({
name: x.name,
type: "number",
value: x.default || 0,
value: x.default ?? 0,
});
} else if (x.type === "switch") {
pageVars.push({
@ -36,7 +36,7 @@ export function collectPageVars(content) {
pageVars.push({
name: x.name,
type: "string",
value: x.default || "",
value: x.default ?? "",
});
} else if (x.children) {
collect(x.children);

View file

@ -37,7 +37,7 @@ export const categoryMapping = {
} as const;
export function addSkinTone(emoji: string, skinTone?: number) {
const chosenSkinTone = skinTone || defaultStore.state.reactionPickerSkinTone;
const chosenSkinTone = skinTone ?? defaultStore.state.reactionPickerSkinTone;
const skinToneModifiers = [
"",
emojiComponents.light_skin_tone,
@ -51,7 +51,7 @@ export function addSkinTone(emoji: string, skinTone?: number) {
"",
);
if (individualData[strippedEmoji].skin_tone_support) {
return strippedEmoji + (skinToneModifiers[chosenSkinTone - 1] || "");
return strippedEmoji + (skinToneModifiers[chosenSkinTone - 1] ?? "");
} else {
return emoji;
}
@ -62,7 +62,7 @@ const newData = {};
for (const originalCategory of Object.keys(data)) {
const newCategory = categoryMapping[originalCategory];
if (newCategory) {
newData[newCategory] = newData[newCategory] || [];
newData[newCategory] = newData[newCategory] ?? [];
for (const emojiIndex of Object.keys(data[originalCategory])) {
const emojiObj = { ...data[originalCategory][emojiIndex] };
emojiObj.category = newCategory;
@ -79,8 +79,8 @@ export const emojilist: UnicodeEmojiDef[] = Object.keys(newData).reduce(
emoji: item.emoji,
slug: item.slug,
category: item.category,
skin_tone_support: item.skin_tone_support || false,
keywords: item.keywords || [],
skin_tone_support: item.skin_tone_support ?? false,
keywords: item.keywords ?? [],
};
});
return acc.concat(categoryItems);
@ -92,6 +92,6 @@ export function getNicelyLabeledCategory(internalName) {
return (
Object.keys(categoryMapping).find(
(key) => categoryMapping[key] === internalName,
) || internalName
) ?? internalName
);
}

View file

@ -28,7 +28,7 @@ function formatLocaleString(date: Date, format: string): string {
].includes(kind)
) {
return date.toLocaleString(window.navigator.language, {
[kind]: option || defaultLocaleStringFormats[kind],
[kind]: option ?? defaultLocaleStringFormats[kind],
});
} else {
return match;
@ -55,8 +55,14 @@ export function formatDateTimeString(date: Date, format: string): string {
.replace(/d/g, date.getDate().toString())
.replace(/HH/g, `0${date.getHours()}`.slice(-2))
.replace(/H/g, date.getHours().toString())
.replace(/hh/g, `0${date.getHours() % 12 || 12}`.slice(-2))
.replace(/h/g, (date.getHours() % 12 || 12).toString())
.replace(
/hh/g,
`0${date.getHours() % 12 === 0 ? 12 : date.getHours() % 12}`.slice(-2),
)
.replace(
/h/g,
(date.getHours() % 12 === 0 ? 12 : date.getHours() % 12).toString(),
)
.replace(/mm/g, `0${date.getMinutes()}`.slice(-2))
.replace(/m/g, date.getMinutes().toString())
.replace(/ss/g, `0${date.getSeconds()}`.slice(-2))

View file

@ -266,7 +266,7 @@ export function getNoteMenu(props: {
props.translating.value = true;
props.translation.value = await translate_(
appearNote.id,
translateLang || lang || navigator.language,
translateLang ?? lang ?? navigator.language,
);
// use UI language as the second translation target
@ -274,7 +274,7 @@ export function getNoteMenu(props: {
translateLang != null &&
lang != null &&
translateLang !== lang &&
(!props.translation.value ||
(props.translation.value == null ||
props.translation.value.sourceLang.toLowerCase() ===
translateLang.slice(0, 2))
)
@ -349,7 +349,7 @@ export function getNoteMenu(props: {
},
),
isAppearAuthor
? ($i.pinnedNoteIds || []).includes(appearNote.id)
? ($i.pinnedNoteIds ?? []).includes(appearNote.id)
? {
icon: `${icon("ph-push-pin")}`,
text: i18n.ts.unpin,
@ -368,12 +368,12 @@ export function getNoteMenu(props: {
action: translate,
}
: undefined,
appearNote.url || appearNote.uri
appearNote.url ?? appearNote.uri
? {
icon: `${icon("ph-arrow-square-out")}`,
text: i18n.ts.showOnRemote,
action: () => {
window.open(appearNote.url || appearNote.uri, "_blank");
window.open(appearNote.url ?? appearNote.uri, "_blank");
},
}
: undefined,
@ -392,7 +392,7 @@ export function getNoteMenu(props: {
text: i18n.ts.copyLink,
action: copyLink,
},
appearNote.url || appearNote.uri
appearNote.url ?? appearNote.uri
? {
icon: `${icon("ph-link-simple")}`,
text: `${i18n.ts.copyLink} (${i18n.ts.origin})`,
@ -425,8 +425,8 @@ export function getNoteMenu(props: {
text: i18n.ts.reportAbuse,
action: () => {
const u =
appearNote.url ||
appearNote.uri ||
appearNote.url ??
appearNote.uri ??
`${url}/notes/${appearNote.id}`;
os.popup(
defineAsyncComponent(
@ -490,12 +490,12 @@ export function getNoteMenu(props: {
].filter((x) => x !== undefined);
} else {
menu = [
appearNote.url || appearNote.uri
appearNote.url ?? appearNote.uri
? {
icon: `${icon("ph-arrow-square-out")}`,
text: i18n.ts.showOnRemote,
action: () => {
window.open(appearNote.url || appearNote.uri, "_blank");
window.open(appearNote.url ?? appearNote.uri, "_blank");
},
}
: undefined,
@ -509,7 +509,7 @@ export function getNoteMenu(props: {
text: i18n.ts.copyLink,
action: copyLink,
},
appearNote.url || appearNote.uri
appearNote.url ?? appearNote.uri
? {
icon: `${icon("ph-link-simple")}`,
text: `${i18n.ts.copyLink} (${i18n.ts.origin})`,

View file

@ -21,7 +21,7 @@ export const getNoteSummary = (note: firefish.entities.Note): string => {
}
// ファイルが添付されているとき
if ((note.files || []).length !== 0) {
if ((note.files ?? []).length !== 0) {
const len = note.files?.length;
summary += ` 📎${len !== 1 ? ` (${len})` : ""}`;
}

View file

@ -227,14 +227,14 @@ export function getUserMenu(user, router: Router = mainRouter) {
{
type: "label",
text: user.host
? `@${user.username}@${user.host || host}`
? `@${user.username}@${user.host ?? host}`
: `@${user.username}`,
},
{
icon: `${icon("ph-at")}`,
text: i18n.ts.copyUsername,
action: () => {
copyToClipboard(`@${user.username}@${user.host || host}`);
copyToClipboard(`@${user.username}@${user.host ?? host}`);
},
},
{

View file

@ -2,5 +2,5 @@ export default function (user: {
name?: string | null;
username: string;
}): string {
return user.name || user.username;
return user.name ?? user.username;
}

View file

@ -79,7 +79,7 @@ export class Hpml {
? `${opts.url}/@${this.page.user.username}/pages/${this.page.name}`
: "",
LOGIN: opts.visitor != null,
NAME: opts.visitor ? opts.visitor.name || opts.visitor.username : "",
NAME: opts.visitor ? opts.visitor.name ?? opts.visitor.username : "",
USERNAME: opts.visitor ? opts.visitor.username : "",
USERID: opts.visitor ? opts.visitor.id : "",
NOTES_COUNT: opts.visitor ? opts.visitor.notesCount : 0,
@ -187,11 +187,11 @@ export class Hpml {
}
if (expr.type === "text" || expr.type === "multiLineText") {
return this._interpolateScope(expr.value || "", scope);
return this._interpolateScope(expr.value ?? "", scope);
}
if (expr.type === "textList") {
return this._interpolateScope(expr.value || "", scope)
return this._interpolateScope(expr.value ?? "", scope)
.trim()
.split("\n");
}

View file

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

View file

@ -504,7 +504,7 @@ export function initHpmlLib(
strPick: (a: string, b: number) => a[b - 1],
strReplace: (a: string, b: string, c: string) => a.split(b).join(c),
strReverse: (a: string) => a.split("").reverse().join(""),
join: (texts: string[], separator: string) => texts.join(separator || ""),
join: (texts: string[], separator: string) => texts.join(separator ?? ""),
stringToNumber: (a: string) => parseInt(a),
numberToString: (a: number) => a.toString(),
splitStrByLine: (a: string) => a.split("\n"),

View file

@ -30,7 +30,7 @@ export class HpmlTypeChecker {
public typeCheck(v: Expr): TypeError | null {
if (isLiteralValue(v)) return null;
const def = funcDefs[v.type || ""];
const def = funcDefs[v.type ?? ""];
if (def == null) {
throw new Error(`Unknown type: ${v.type}`);
}
@ -66,7 +66,7 @@ export class HpmlTypeChecker {
@autobind
public getExpectedType(v: Expr, slot: number): Type {
const def = funcDefs[v.type || ""];
const def = funcDefs[v.type ?? ""];
if (def == null) {
throw new Error(`Unknown type: ${v.type}`);
}
@ -86,7 +86,7 @@ export class HpmlTypeChecker {
}
if (typeof def.in[slot] === "number") {
return generic[def.in[slot]] || null;
return generic[def.in[slot]] ?? null;
} else {
return def.in[slot];
}
@ -110,7 +110,7 @@ export class HpmlTypeChecker {
return pageVar.type;
}
const envVar = envVarsDef[v.value || ""];
const envVar = envVarsDef[v.value ?? ""];
if (envVar !== undefined) {
return envVar;
}

View file

@ -90,7 +90,7 @@ export function physics(container: HTMLElement) {
objEl.offsetHeight,
{
chamfer: {
radius: parseInt(style.borderRadius || "0", 10),
radius: parseInt(style.borderRadius ?? "0", 10),
},
restitution: 0.5,
},

View file

@ -36,7 +36,7 @@ export function isBottomVisible(
}
export function onScrollTop(el: Element, cb) {
const container = getScrollContainer(el) || window;
const container = getScrollContainer(el) ?? window;
const onScroll = (ev) => {
if (!document.body.contains(el)) return;
if (isTopVisible(el)) {
@ -48,7 +48,7 @@ export function onScrollTop(el: Element, cb) {
}
export function onScrollBottom(el: Element, cb) {
const container = getScrollContainer(el) || window;
const container = getScrollContainer(el) ?? window;
const onScroll = (ev) => {
if (!document.body.contains(el)) return;
const pos = getScrollPosition(el);

View file

@ -44,7 +44,7 @@ export function uploadFile(
reader.onload = async (ev) => {
const ctx = reactive<Uploading>({
id,
name: name || file.name || "untitled",
name: name ?? file.name ?? "untitled",
progressMax: undefined,
progressValue: undefined,
img: window.URL.createObjectURL(file),
@ -78,7 +78,7 @@ export function uploadFile(
const formData = new FormData();
formData.append("force", "true");
formData.append("file", resizedImage || file);
formData.append("file", resizedImage ?? file);
formData.append("name", ctx.name);
if (folder) formData.append("folderId", folder);

View file

@ -24,14 +24,14 @@ export function useNoteCapture(props: {
const reaction = body.reaction;
if (body.emoji) {
const emojis = note.value.emojis || [];
const emojis = note.value.emojis ?? [];
if (!emojis.includes(body.emoji)) {
note.value.emojis = [...emojis, body.emoji];
}
}
// TODO: reactionsプロパティがない場合ってあったっけ なければ || {} は消せる
const currentCount = note.value.reactions?.[reaction] || 0;
// TODO: reactionsプロパティがない場合ってあったっけ
const currentCount = note.value.reactions?.[reaction] ?? 0;
note.value.reactions[reaction] = currentCount + 1;
@ -44,8 +44,8 @@ export function useNoteCapture(props: {
case "unreacted": {
const reaction = body.reaction;
// TODO: reactionsプロパティがない場合ってあったっけ なければ || {} は消せる
const currentCount = note.value.reactions?.[reaction] || 0;
// TODO: reactionsプロパティがない場合ってあったっけ
const currentCount = note.value.reactions?.[reaction] ?? 0;
note.value.reactions[reaction] = Math.max(0, currentCount - 1);

View file

@ -5,7 +5,7 @@ import { $i, isSignedIn } from "@/reactiveAccount";
const lsCacheKey = isSignedIn ? `themes:${$i.id}` : "";
export function getThemes(): Theme[] {
return JSON.parse(localStorage.getItem(lsCacheKey) || "[]");
return JSON.parse(localStorage.getItem(lsCacheKey) ?? "[]");
}
export async function fetchThemes(): Promise<void> {

View file

@ -146,7 +146,7 @@
></i>
</button>
<!-- <button v-click-anime v-tooltip.noDelay.right="$instance.name ?? i18n.ts.instance" class="item _button instance" @click="openInstanceMenu">
<img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/>
<img :src="$instance.faviconUrl ?? $instance.iconUrl ?? '/favicon.ico'" alt="" class="icon"/>
</button> -->
<!-- <button v-click-anime v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$i" class="account"/><MkAcct class="text" :user="$i"/>

View file

@ -41,8 +41,8 @@
</p>
</div>
<progress
:value="ctx.progressValue || 0"
:max="ctx.progressMax || 0"
:value="ctx.progressValue ?? 0"
:max="ctx.progressMax ?? 0"
:class="{
initing: ctx.progressValue === undefined,
waiting:

View file

@ -16,7 +16,11 @@
<div v-if="meta" class="about">
<div
class="desc"
v-html="meta.description || i18n.ts.introFirefish"
v-html="
meta.description !== ''
? meta.description
: i18n.ts.introFirefish
"
></div>
</div>
<div class="action">

View file

@ -86,10 +86,9 @@ import XKanban from "./kanban.vue";
import { host, instanceName } from "@/config";
import { search } from "@/scripts/search";
import * as os from "@/os";
import { instance } from "@/instance";
import XSigninDialog from "@/components/MkSigninDialog.vue";
import XSignupDialog from "@/components/MkSignupDialog.vue";
import { ColdDeviceStorage, defaultStore } from "@/store";
import { defaultStore } from "@/store";
import { mainRouter } from "@/router";
import type { PageMetadata } from "@/scripts/page-metadata";
import { provideMetadataReceiver } from "@/scripts/page-metadata";
@ -108,29 +107,11 @@ provideMetadataReceiver((info) => {
}
});
const announcements = {
endpoint: "announcements",
limit: 10,
};
const isTimelineAvailable =
!instance.disableLocalTimeline ||
!instance.disableRecommendedTimeline ||
!instance.disableGlobalTimeline;
const showMenu = ref(false);
const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD);
const narrow = ref(window.innerWidth < 1280);
const meta = ref();
const keymap = computed(() => {
return {
d: () => {
if (ColdDeviceStorage.get("syncDeviceDarkMode")) return;
defaultStore.set("darkMode", !defaultStore.state.darkMode);
},
s: search,
};
});
const root = computed(() => mainRouter.currentRoute.value.name === "index");
os.api("meta", { detail: true }).then((res) => {
@ -227,9 +208,6 @@ defineExpose({
flex: 1;
min-width: 0;
> .banner {
}
> .contents {
position: relative;
z-index: 1;

View file

@ -26,7 +26,11 @@
<div v-if="meta" class="about">
<div
class="desc"
v-html="meta.description || i18n.ts.introFirefish"
v-html="
meta.description !== ''
? meta.description
: i18n.ts.introFirefish
"
></div>
</div>
<div class="action">

View file

@ -33,7 +33,7 @@
>{{ instance.host }}</a
>
<p>
{{ instance.softwareName || "?" }}
{{ instance.softwareName ?? "?" }}
{{ instance.softwareVersion }}
</p>
</div>

View file

@ -9,8 +9,8 @@
<div :class="$style.iconContainer">
<img
:src="
$instance.iconUrl ||
$instance.faviconUrl ||
$instance.faviconUrl ??
$instance.iconUrl ??
'/favicon.ico'
"
alt="Instance logo"