Merge branch 'develop' into enh-14784
This commit is contained in:
commit
9841c6e255
|
@ -4,6 +4,8 @@
|
|||
-
|
||||
|
||||
### Client
|
||||
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
|
||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751)
|
||||
- Enhance: ノートの公開範囲に応じて色分けできるように
|
||||
|
||||
### Server
|
||||
|
|
|
@ -30,6 +30,7 @@ import type {
|
|||
EndedPollNotificationQueue,
|
||||
InboxQueue,
|
||||
ObjectStorageQueue,
|
||||
RelationshipQueue,
|
||||
SystemQueue,
|
||||
UserWebhookDeliverQueue,
|
||||
SystemWebhookDeliverQueue,
|
||||
|
@ -121,6 +122,7 @@ export class ClientServerService {
|
|||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||
@Inject('queue:db') public dbQueue: DbQueue,
|
||||
@Inject('queue:relationship') public relationshipQueue: RelationshipQueue,
|
||||
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
|
||||
@Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
|
||||
@Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
|
||||
|
@ -248,6 +250,7 @@ export class ClientServerService {
|
|||
this.deliverQueue,
|
||||
this.inboxQueue,
|
||||
this.dbQueue,
|
||||
this.relationshipQueue,
|
||||
this.objectStorageQueue,
|
||||
this.userWebhookDeliverQueue,
|
||||
this.systemWebhookDeliverQueue,
|
||||
|
|
|
@ -64,26 +64,30 @@ const showBody = ref(props.expanded);
|
|||
const ignoreOmit = ref(false);
|
||||
const omitted = ref(false);
|
||||
|
||||
function enter(el) {
|
||||
function enter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = 0;
|
||||
el.style.height = '0';
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = Math.min(elementHeight, props.maxHeight ?? Infinity) + 'px';
|
||||
el.style.height = `${Math.min(elementHeight, props.maxHeight ?? Infinity)}px`;
|
||||
}
|
||||
|
||||
function afterEnter(el) {
|
||||
el.style.height = null;
|
||||
function afterEnter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.height = '';
|
||||
}
|
||||
|
||||
function leave(el) {
|
||||
function leave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = elementHeight + 'px';
|
||||
el.style.height = `${elementHeight}px`;
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = 0;
|
||||
el.style.height = '0';
|
||||
}
|
||||
|
||||
function afterLeave(el) {
|
||||
el.style.height = null;
|
||||
function afterLeave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.height = '';
|
||||
}
|
||||
|
||||
const calcOmit = () => {
|
||||
|
|
|
@ -128,14 +128,14 @@ export default defineComponent({
|
|||
return children;
|
||||
};
|
||||
|
||||
function onBeforeLeave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
function onBeforeLeave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.top = `${el.offsetTop}px`;
|
||||
el.style.left = `${el.offsetLeft}px`;
|
||||
}
|
||||
|
||||
function onLeaveCancelled(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
function onLeaveCancelled(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.top = '';
|
||||
el.style.left = '';
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div ref="rootEl" :class="$style.root">
|
||||
<header :class="$style.header" class="_button" :style="{ background: bg }" @click="showBody = !showBody">
|
||||
<header :class="$style.header" class="_button" @click="showBody = !showBody">
|
||||
<div :class="$style.title"><div><slot name="header"></slot></div></div>
|
||||
<div :class="$style.divider"></div>
|
||||
<button class="_button" :class="$style.button">
|
||||
|
@ -32,21 +32,23 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||
|
||||
const miLocalStoragePrefix = 'ui:folder:' as const;
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
expanded?: boolean;
|
||||
persistKey?: string;
|
||||
persistKey?: string | null;
|
||||
}>(), {
|
||||
expanded: true,
|
||||
persistKey: null,
|
||||
});
|
||||
|
||||
const rootEl = shallowRef<HTMLDivElement>();
|
||||
const bg = ref<string>();
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const parentBg = ref<string | null>(null);
|
||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
|
||||
|
||||
watch(showBody, () => {
|
||||
|
@ -55,47 +57,34 @@ watch(showBody, () => {
|
|||
}
|
||||
});
|
||||
|
||||
function enter(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
function enter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = '0';
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = elementHeight + 'px';
|
||||
el.style.height = `${elementHeight}px`;
|
||||
}
|
||||
|
||||
function afterEnter(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
el.style.height = 'unset';
|
||||
function afterEnter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.height = '';
|
||||
}
|
||||
|
||||
function leave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
function leave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = elementHeight + 'px';
|
||||
el.style.height = `${elementHeight}px`;
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = '0';
|
||||
}
|
||||
|
||||
function afterLeave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
el.style.height = 'unset';
|
||||
function afterLeave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.height = '';
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
function getParentBg(el?: HTMLElement | null): string {
|
||||
if (el == null || el.tagName === 'BODY') return 'var(--MI_THEME-bg)';
|
||||
const background = el.style.background || el.style.backgroundColor;
|
||||
if (background) {
|
||||
return background;
|
||||
} else {
|
||||
return getParentBg(el.parentElement);
|
||||
}
|
||||
}
|
||||
|
||||
const rawBg = getParentBg(rootEl.value);
|
||||
const _bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||
_bg.setAlpha(0.85);
|
||||
bg.value = _bg.toRgbString();
|
||||
parentBg.value = getBgColor(rootEl.value?.parentElement);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -121,6 +110,7 @@ onMounted(() => {
|
|||
top: var(--MI-stickyTop, 0px);
|
||||
-webkit-backdrop-filter: var(--MI-blur, blur(8px));
|
||||
backdrop-filter: var(--MI-blur, blur(20px));
|
||||
background-color: color(from v-bind("parentBg ?? 'var(--bg)'") srgb r g b / 0.85);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
@ -56,8 +56,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, shallowRef, ref } from 'vue';
|
||||
import { nextTick, onMounted, ref, shallowRef } from 'vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
defaultOpen?: boolean;
|
||||
|
@ -69,40 +70,35 @@ const props = withDefaults(defineProps<{
|
|||
withSpacer: true,
|
||||
});
|
||||
|
||||
const getBgColor = (el: HTMLElement) => {
|
||||
const style = window.getComputedStyle(el);
|
||||
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
||||
return style.backgroundColor;
|
||||
} else {
|
||||
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const bgSame = ref(false);
|
||||
const opened = ref(props.defaultOpen);
|
||||
const openedAtLeastOnce = ref(props.defaultOpen);
|
||||
|
||||
function enter(el) {
|
||||
function enter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = 0;
|
||||
el.style.height = '0';
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = Math.min(elementHeight, props.maxHeight ?? Infinity) + 'px';
|
||||
el.style.height = `${Math.min(elementHeight, props.maxHeight ?? Infinity)}px`;
|
||||
}
|
||||
|
||||
function afterEnter(el) {
|
||||
el.style.height = null;
|
||||
function afterEnter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.height = '';
|
||||
}
|
||||
|
||||
function leave(el) {
|
||||
function leave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementHeight = el.getBoundingClientRect().height;
|
||||
el.style.height = elementHeight + 'px';
|
||||
el.style.height = `${elementHeight}px`;
|
||||
el.offsetHeight; // reflow
|
||||
el.style.height = 0;
|
||||
el.style.height = '0';
|
||||
}
|
||||
|
||||
function afterLeave(el) {
|
||||
el.style.height = null;
|
||||
function afterLeave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.height = '';
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
|
@ -117,7 +113,7 @@ function toggle() {
|
|||
|
||||
onMounted(() => {
|
||||
const computedStyle = getComputedStyle(document.documentElement);
|
||||
const parentBg = getBgColor(rootEl.value!.parentElement!);
|
||||
const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent';
|
||||
const myBg = computedStyle.getPropertyValue('--MI_THEME-panel');
|
||||
bgSame.value = parentBg === myBg;
|
||||
});
|
||||
|
|
|
@ -53,7 +53,7 @@ export type Tab = {
|
|||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, watch, nextTick, shallowRef } from 'vue';
|
||||
import { nextTick, onMounted, onUnmounted, shallowRef, watch } from 'vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
|
@ -120,14 +120,14 @@ function onTabWheel(ev: WheelEvent) {
|
|||
|
||||
let entering = false;
|
||||
|
||||
async function enter(element: Element) {
|
||||
async function enter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
entering = true;
|
||||
const el = element as HTMLElement;
|
||||
const elementWidth = el.getBoundingClientRect().width;
|
||||
el.style.width = '0';
|
||||
el.style.paddingLeft = '0';
|
||||
el.offsetWidth; // force reflow
|
||||
el.style.width = elementWidth + 'px';
|
||||
el.offsetWidth; // reflow
|
||||
el.style.width = `${elementWidth}px`;
|
||||
el.style.paddingLeft = '';
|
||||
nextTick(() => {
|
||||
entering = false;
|
||||
|
@ -136,22 +136,23 @@ async function enter(element: Element) {
|
|||
setTimeout(renderTab, 170);
|
||||
}
|
||||
|
||||
function afterEnter(element: Element) {
|
||||
//el.style.width = '';
|
||||
function afterEnter(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
// element.style.width = '';
|
||||
}
|
||||
|
||||
async function leave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
async function leave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
const elementWidth = el.getBoundingClientRect().width;
|
||||
el.style.width = elementWidth + 'px';
|
||||
el.style.width = `${elementWidth}px`;
|
||||
el.style.paddingLeft = '';
|
||||
el.offsetWidth; // force reflow
|
||||
el.offsetWidth; // reflow
|
||||
el.style.width = '0';
|
||||
el.style.paddingLeft = '0';
|
||||
}
|
||||
|
||||
function afterLeave(element: Element) {
|
||||
const el = element as HTMLElement;
|
||||
function afterLeave(el: Element) {
|
||||
if (!(el instanceof HTMLElement)) return;
|
||||
el.style.width = '';
|
||||
}
|
||||
|
||||
|
|
|
@ -4,19 +4,11 @@
|
|||
*/
|
||||
|
||||
import { Directive } from 'vue';
|
||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
const getBgColor = (el: HTMLElement) => {
|
||||
const style = window.getComputedStyle(el);
|
||||
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
||||
return style.backgroundColor;
|
||||
} else {
|
||||
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const parentBg = getBgColor(src.parentElement);
|
||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||
|
||||
const myBg = window.getComputedStyle(src).backgroundColor;
|
||||
|
||||
|
|
|
@ -4,19 +4,11 @@
|
|||
*/
|
||||
|
||||
import { Directive } from 'vue';
|
||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
const getBgColor = (el: HTMLElement) => {
|
||||
const style = window.getComputedStyle(el);
|
||||
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
||||
return style.backgroundColor;
|
||||
} else {
|
||||
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const parentBg = getBgColor(src.parentElement);
|
||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||
|
||||
const myBg = window.getComputedStyle(src).backgroundColor;
|
||||
|
||||
|
|
|
@ -4,19 +4,11 @@
|
|||
*/
|
||||
|
||||
import { Directive } from 'vue';
|
||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
const getBgColor = (el: HTMLElement) => {
|
||||
const style = window.getComputedStyle(el);
|
||||
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
||||
return style.backgroundColor;
|
||||
} else {
|
||||
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const parentBg = getBgColor(src.parentElement);
|
||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||
|
||||
const myBg = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel');
|
||||
|
||||
|
|
|
@ -5,10 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header>
|
||||
<MkPageHeader/>
|
||||
</template>
|
||||
<MKSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
|
||||
<template #header><MkPageHeader/></template>
|
||||
<MkSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
|
||||
<div :class="$style.root">
|
||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||
<div :class="$style.text">
|
||||
|
@ -16,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
{{ i18n.ts.nothing }}
|
||||
</div>
|
||||
</div>
|
||||
</MKSpacer>
|
||||
</MkSpacer>
|
||||
<MkSpacer v-else :contentMax="800">
|
||||
<div class="_gaps_m" style="text-align: center;">
|
||||
<div v-if="resetCycle && inviteLimit">{{ i18n.tsx.inviteLimitResetCycle({ time: resetCycle, limit: inviteLimit }) }}</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
||||
<MkSpacer v-if="error != null" :contentMax="1200">
|
||||
<div :class="$style.root">
|
||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||
<p :class="$style.text">
|
||||
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
{{ i18n.ts.nothing }}
|
||||
</p>
|
||||
</div>
|
||||
</MKSpacer>
|
||||
</MkSpacer>
|
||||
<MkSpacer v-else-if="list" :contentMax="700" :class="$style.main">
|
||||
<div v-if="list" class="members _margin">
|
||||
<div :class="$style.member_text">{{ i18n.ts.members }}</div>
|
||||
|
@ -50,7 +50,7 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const list = ref<Misskey.entities.UserList | null>(null);
|
||||
const error = ref();
|
||||
const error = ref<unknown | null>(null);
|
||||
const users = ref<Misskey.entities.UserDetailed[]>([]);
|
||||
|
||||
function fetchList(): void {
|
||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template>
|
||||
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
||||
<MkSpacer v-if="error != null" :contentMax="1200">
|
||||
<div :class="$style.root">
|
||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||
<p :class="$style.text">
|
||||
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
{{ error }}
|
||||
</p>
|
||||
</div>
|
||||
</MKSpacer>
|
||||
</MkSpacer>
|
||||
<MkSpacer v-else-if="tab === 'users'" :contentMax="1200">
|
||||
<div class="_gaps_s">
|
||||
<div v-if="role">{{ role.description }}</div>
|
||||
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</MkSpacer>
|
||||
<MkSpacer v-else-if="tab === 'timeline'" :contentMax="700">
|
||||
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.role"/>
|
||||
<MkTimeline v-if="visible" ref="timeline" src="role" :role="props.roleId"/>
|
||||
<div v-else-if="!visible" class="_fullinfo">
|
||||
<img :src="infoImageUrl" class="_ghost"/>
|
||||
<div>{{ i18n.ts.nothing }}</div>
|
||||
|
@ -47,23 +47,24 @@ import { instanceName } from '@@/js/config.js';
|
|||
import { serverErrorImageUrl, infoImageUrl } from '@/instance.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
role: string;
|
||||
roleId: string;
|
||||
initialTab?: string;
|
||||
}>(), {
|
||||
initialTab: 'users',
|
||||
});
|
||||
|
||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||
const tab = ref(props.initialTab);
|
||||
const role = ref<Misskey.entities.Role>();
|
||||
const error = ref();
|
||||
const role = ref<Misskey.entities.Role | null>(null);
|
||||
const error = ref<string | null>(null);
|
||||
const visible = ref(false);
|
||||
|
||||
watch(() => props.role, () => {
|
||||
watch(() => props.roleId, () => {
|
||||
misskeyApi('roles/show', {
|
||||
roleId: props.role,
|
||||
roleId: props.roleId,
|
||||
}).then(res => {
|
||||
role.value = res;
|
||||
document.title = `${role.value.name} | ${instanceName}`;
|
||||
error.value = null;
|
||||
visible.value = res.isExplorable && res.isPublic;
|
||||
}).catch((err) => {
|
||||
if (err.code === 'NO_SUCH_ROLE') {
|
||||
|
@ -71,7 +72,6 @@ watch(() => props.role, () => {
|
|||
} else {
|
||||
error.value = i18n.ts.somethingHappened;
|
||||
}
|
||||
document.title = `${error.value} | ${instanceName}`;
|
||||
});
|
||||
}, { immediate: true });
|
||||
|
||||
|
@ -79,7 +79,7 @@ const users = computed(() => ({
|
|||
endpoint: 'roles/users' as const,
|
||||
limit: 30,
|
||||
params: {
|
||||
roleId: props.role,
|
||||
roleId: props.roleId,
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -94,7 +94,7 @@ const headerTabs = computed(() => [{
|
|||
}]);
|
||||
|
||||
definePageMetadata(() => ({
|
||||
title: role.value ? role.value.name : i18n.ts.role,
|
||||
title: role.value ? role.value.name : (error.value ?? i18n.ts.role),
|
||||
icon: 'ti ti-badge',
|
||||
}));
|
||||
</script>
|
||||
|
|
|
@ -217,7 +217,7 @@ const routes: RouteDef[] = [{
|
|||
component: page(() => import('@/pages/theme-editor.vue')),
|
||||
loginRequired: true,
|
||||
}, {
|
||||
path: '/roles/:role',
|
||||
path: '/roles/:roleId',
|
||||
component: page(() => import('@/pages/role.vue')),
|
||||
}, {
|
||||
path: '/user-tags/:tag',
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
export const getBgColor = (elem?: Element | null | undefined): string | null => {
|
||||
if (elem == null) return null;
|
||||
|
||||
const { backgroundColor: bg } = window.getComputedStyle(elem);
|
||||
|
||||
if (bg && tinycolor(bg).getAlpha() !== 0) {
|
||||
return bg;
|
||||
}
|
||||
|
||||
return getBgColor(elem.parentElement);
|
||||
};
|
Loading…
Reference in New Issue