forked from mirrors/misskey
Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
import type { Directive } from 'vue';
|
||||
import { getBgColor } from '@/utility/get-bg-color.js';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
export const adaptiveBgDirective = {
|
||||
mounted(src) {
|
||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||
|
||||
const myBg = window.getComputedStyle(src).backgroundColor;
|
||||
@@ -18,4 +18,4 @@ export default {
|
||||
src.style.backgroundColor = myBg;
|
||||
}
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElement>;
|
||||
|
||||
@@ -9,8 +9,8 @@ import { globalEvents } from '@/events.js';
|
||||
|
||||
const handlerMap = new WeakMap<any, any>();
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
export const adaptiveBorderDirective = {
|
||||
mounted(src) {
|
||||
function calc() {
|
||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||
|
||||
@@ -30,7 +30,7 @@ export default {
|
||||
globalEvents.on('themeChanged', calc);
|
||||
},
|
||||
|
||||
unmounted(src, binding, vn) {
|
||||
unmounted(src) {
|
||||
globalEvents.off('themeChanged', handlerMap.get(src));
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElement>;
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
import type { Directive } from 'vue';
|
||||
|
||||
export default {
|
||||
beforeMount(src, binding, vn) {
|
||||
export const animDirective = {
|
||||
beforeMount(src) {
|
||||
src.style.opacity = '0';
|
||||
src.style.transform = 'scale(0.9)';
|
||||
// ページネーションと相性が悪いので
|
||||
@@ -14,10 +14,10 @@ export default {
|
||||
src.classList.add('_zoom');
|
||||
},
|
||||
|
||||
mounted(src, binding, vn) {
|
||||
mounted(src) {
|
||||
window.setTimeout(() => {
|
||||
src.style.opacity = '1';
|
||||
src.style.transform = 'none';
|
||||
}, 1);
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElement>;
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
import { throttle } from 'throttle-debounce';
|
||||
import type { Directive } from 'vue';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
interface HTMLElementWithObserver extends HTMLElement {
|
||||
_observer_?: IntersectionObserver;
|
||||
}
|
||||
|
||||
export const appearDirective = {
|
||||
mounted(src, binding) {
|
||||
const fn = binding.value;
|
||||
if (fn == null) return;
|
||||
|
||||
const check = throttle(1000, (entries) => {
|
||||
const check = throttle<IntersectionObserverCallback>(1000, (entries) => {
|
||||
if (entries.some(entry => entry.isIntersecting)) {
|
||||
fn();
|
||||
}
|
||||
@@ -24,7 +28,7 @@ export default {
|
||||
src._observer_ = observer;
|
||||
},
|
||||
|
||||
unmounted(src, binding, vn) {
|
||||
unmounted(src) {
|
||||
if (src._observer_) src._observer_.disconnect();
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElementWithObserver, () => void>;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import type { Directive } from 'vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
|
||||
export default {
|
||||
mounted(el: HTMLElement, binding, vn) {
|
||||
export const clickAnimeDirective = {
|
||||
mounted(el) {
|
||||
if (!prefer.s.animation) return;
|
||||
|
||||
const target = el.children[0];
|
||||
@@ -37,4 +37,4 @@ export default {
|
||||
target.classList.add('_anime_bounce_standBy');
|
||||
});
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElement>;
|
||||
|
||||
@@ -6,8 +6,12 @@
|
||||
import type { Directive } from 'vue';
|
||||
import { getScrollContainer, getScrollPosition } from '@@/js/scroll.js';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
interface HTMLElementWithRO extends HTMLElement {
|
||||
_ro_?: ResizeObserver;
|
||||
}
|
||||
|
||||
export const followAppendDirective = {
|
||||
mounted(src, binding) {
|
||||
if (binding.value === false) return;
|
||||
|
||||
let isBottom = true;
|
||||
@@ -34,7 +38,7 @@ export default {
|
||||
src._ro_ = ro;
|
||||
},
|
||||
|
||||
unmounted(src, binding, vn) {
|
||||
unmounted(src) {
|
||||
if (src._ro_) src._ro_.unobserve(src);
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElementWithRO, boolean>;
|
||||
|
||||
@@ -37,8 +37,10 @@ function calc(src: Element) {
|
||||
info.fn(width, height);
|
||||
}
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
type SizeCallback = (w: number, h: number) => void;
|
||||
|
||||
export const getSizeDirective = {
|
||||
mounted(src, binding) {
|
||||
const resize = new ResizeObserver((entries, observer) => {
|
||||
calc(src);
|
||||
});
|
||||
@@ -48,7 +50,7 @@ export default {
|
||||
calc(src);
|
||||
},
|
||||
|
||||
unmounted(src, binding, vn) {
|
||||
unmounted(src, binding) {
|
||||
binding.value(0, 0);
|
||||
const info = mountings.get(src);
|
||||
if (!info) return;
|
||||
@@ -56,4 +58,4 @@ export default {
|
||||
if (info.intersection) info.intersection.disconnect();
|
||||
mountings.delete(src);
|
||||
},
|
||||
} as Directive<Element, (w: number, h: number) => void>;
|
||||
} as Directive<Element, SizeCallback>;
|
||||
|
||||
@@ -5,8 +5,14 @@
|
||||
|
||||
import type { Directive } from 'vue';
|
||||
import { makeHotkey } from '@/utility/hotkey.js';
|
||||
import type { Keymap } from '@/utility/hotkey.js';
|
||||
|
||||
export default {
|
||||
interface HTMLElementWithHotkey extends HTMLElement {
|
||||
_hotkey_global?: boolean;
|
||||
_keyHandler?: (ev: KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
export const hotkeyDirective = {
|
||||
mounted(el, binding) {
|
||||
el._hotkey_global = binding.modifiers.global === true;
|
||||
|
||||
@@ -20,10 +26,11 @@ export default {
|
||||
},
|
||||
|
||||
unmounted(el) {
|
||||
if (el._keyHandler == null) return;
|
||||
if (el._hotkey_global) {
|
||||
window.document.removeEventListener('keydown', el._keyHandler);
|
||||
} else {
|
||||
el.removeEventListener('keydown', el._keyHandler);
|
||||
}
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElementWithHotkey, Keymap>;
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { App } from 'vue';
|
||||
import type { App, Directive } from 'vue';
|
||||
|
||||
import userPreview from './user-preview.js';
|
||||
import getSize from './get-size.js';
|
||||
import ripple from './ripple.js';
|
||||
import tooltip from './tooltip.js';
|
||||
import hotkey from './hotkey.js';
|
||||
import appear from './appear.js';
|
||||
import anim from './anim.js';
|
||||
import clickAnime from './click-anime.js';
|
||||
import panel from './panel.js';
|
||||
import adaptiveBorder from './adaptive-border.js';
|
||||
import adaptiveBg from './adaptive-bg.js';
|
||||
import { userPreviewDirective } from './user-preview.js';
|
||||
import { getSizeDirective } from './get-size.js';
|
||||
import { rippleDirective } from './ripple.js';
|
||||
import { tooltipDirective } from './tooltip.js';
|
||||
import { hotkeyDirective } from './hotkey.js';
|
||||
import { appearDirective } from './appear.js';
|
||||
import { animDirective } from './anim.js';
|
||||
import { clickAnimeDirective } from './click-anime.js';
|
||||
import { panelDirective } from './panel.js';
|
||||
import { adaptiveBorderDirective } from './adaptive-border.js';
|
||||
import { adaptiveBgDirective } from './adaptive-bg.js';
|
||||
|
||||
export default function(app: App) {
|
||||
for (const [key, value] of Object.entries(directives)) {
|
||||
@@ -24,16 +24,32 @@ export default function(app: App) {
|
||||
}
|
||||
|
||||
export const directives = {
|
||||
'userPreview': userPreview,
|
||||
'user-preview': userPreview,
|
||||
'get-size': getSize,
|
||||
'ripple': ripple,
|
||||
'tooltip': tooltip,
|
||||
'hotkey': hotkey,
|
||||
'appear': appear,
|
||||
'anim': anim,
|
||||
'click-anime': clickAnime,
|
||||
'panel': panel,
|
||||
'adaptive-border': adaptiveBorder,
|
||||
'adaptive-bg': adaptiveBg,
|
||||
};
|
||||
'userPreview': userPreviewDirective,
|
||||
'user-preview': userPreviewDirective,
|
||||
'get-size': getSizeDirective,
|
||||
'ripple': rippleDirective,
|
||||
'tooltip': tooltipDirective,
|
||||
'hotkey': hotkeyDirective,
|
||||
'appear': appearDirective,
|
||||
'anim': animDirective,
|
||||
'click-anime': clickAnimeDirective,
|
||||
'panel': panelDirective,
|
||||
'adaptive-border': adaptiveBorderDirective,
|
||||
'adaptive-bg': adaptiveBgDirective,
|
||||
} as Record<string, Directive>;
|
||||
|
||||
declare module 'vue' {
|
||||
export interface ComponentCustomProperties {
|
||||
vUserPreview: typeof userPreviewDirective;
|
||||
vGetSize: typeof getSizeDirective;
|
||||
vRipple: typeof rippleDirective;
|
||||
vTooltip: typeof tooltipDirective;
|
||||
vHotkey: typeof hotkeyDirective;
|
||||
vAppear: typeof appearDirective;
|
||||
vAnim: typeof animDirective;
|
||||
vClickAnime: typeof clickAnimeDirective;
|
||||
vPanel: typeof panelDirective;
|
||||
vAdaptiveBorder: typeof adaptiveBorderDirective;
|
||||
vAdaptiveBg: typeof adaptiveBgDirective;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import type { Directive } from 'vue';
|
||||
import { getBgColor } from '@/utility/get-bg-color.js';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
export const panelDirective = {
|
||||
mounted(src) {
|
||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||
|
||||
const myBg = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel');
|
||||
@@ -18,4 +18,4 @@ export default {
|
||||
src.style.backgroundColor = 'var(--MI_THEME-panel)';
|
||||
}
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<HTMLElement>;
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { Directive } from 'vue';
|
||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { popup } from '@/os.js';
|
||||
|
||||
export default {
|
||||
mounted(el, binding, vn) {
|
||||
export const rippleDirective = {
|
||||
mounted(el, binding) {
|
||||
// 明示的に false であればバインドしない
|
||||
if (binding.value === false) return;
|
||||
if (!prefer.s.animation) return;
|
||||
@@ -24,4 +25,4 @@ export default {
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
} as Directive<HTMLElement, boolean | undefined>;
|
||||
|
||||
@@ -14,13 +14,30 @@ import { popup, alert } from '@/os.js';
|
||||
const start = isTouchUsing ? 'touchstart' : 'mouseenter';
|
||||
const end = isTouchUsing ? 'touchend' : 'mouseleave';
|
||||
|
||||
export default {
|
||||
mounted(el: HTMLElement, binding, vn) {
|
||||
type TooltipDirectiveState = {
|
||||
text: string;
|
||||
_close: null | (() => void);
|
||||
showTimer: number | null;
|
||||
hideTimer: number | null;
|
||||
checkTimer: number | null;
|
||||
show: () => void;
|
||||
close: () => void;
|
||||
};
|
||||
|
||||
interface TooltipDirectiveElement extends HTMLElement {
|
||||
_tooltipDirective_?: TooltipDirectiveState;
|
||||
}
|
||||
|
||||
type TooltipDirectiveModifiers = 'left' | 'right' | 'top' | 'bottom' | 'mfm' | 'noDelay';
|
||||
type TooltipDirectiveArg = 'dialog';
|
||||
|
||||
export const tooltipDirective = {
|
||||
mounted(el, binding) {
|
||||
const delay = binding.modifiers.noDelay ? 0 : 100;
|
||||
|
||||
const self = (el as any)._tooltipDirective_ = {} as any;
|
||||
const self = el._tooltipDirective_ = {} as TooltipDirectiveState;
|
||||
|
||||
self.text = binding.value as string;
|
||||
self.text = binding.value;
|
||||
self._close = null;
|
||||
self.showTimer = null;
|
||||
self.hideTimer = null;
|
||||
@@ -28,7 +45,7 @@ export default {
|
||||
|
||||
self.close = () => {
|
||||
if (self._close) {
|
||||
window.clearInterval(self.checkTimer);
|
||||
if (self.checkTimer) window.clearInterval(self.checkTimer);
|
||||
self._close();
|
||||
self._close = null;
|
||||
}
|
||||
@@ -72,8 +89,8 @@ export default {
|
||||
});
|
||||
|
||||
el.addEventListener(start, (ev) => {
|
||||
window.clearTimeout(self.showTimer);
|
||||
window.clearTimeout(self.hideTimer);
|
||||
if (self.showTimer) window.clearTimeout(self.showTimer);
|
||||
if (self.hideTimer) window.clearTimeout(self.hideTimer);
|
||||
if (delay === 0) {
|
||||
self.show();
|
||||
} else {
|
||||
@@ -82,8 +99,8 @@ export default {
|
||||
}, { passive: true });
|
||||
|
||||
el.addEventListener(end, () => {
|
||||
window.clearTimeout(self.showTimer);
|
||||
window.clearTimeout(self.hideTimer);
|
||||
if (self.showTimer) window.clearTimeout(self.showTimer);
|
||||
if (self.hideTimer) window.clearTimeout(self.hideTimer);
|
||||
if (delay === 0) {
|
||||
self.close();
|
||||
} else {
|
||||
@@ -92,18 +109,23 @@ export default {
|
||||
}, { passive: true });
|
||||
|
||||
el.addEventListener('click', () => {
|
||||
window.clearTimeout(self.showTimer);
|
||||
if (self.showTimer) window.clearTimeout(self.showTimer);
|
||||
self.close();
|
||||
});
|
||||
},
|
||||
|
||||
updated(el, binding) {
|
||||
const self = el._tooltipDirective_;
|
||||
if (self == null) return;
|
||||
self.text = binding.value as string;
|
||||
},
|
||||
|
||||
unmounted(el, binding, vn) {
|
||||
unmounted(el) {
|
||||
const self = el._tooltipDirective_;
|
||||
window.clearInterval(self.checkTimer);
|
||||
if (self == null) return;
|
||||
if (self.showTimer) window.clearTimeout(self.showTimer);
|
||||
if (self.hideTimer) window.clearTimeout(self.hideTimer);
|
||||
if (self.checkTimer) window.clearTimeout(self.checkTimer);
|
||||
self.close();
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<TooltipDirectiveElement, string, TooltipDirectiveModifiers, TooltipDirectiveArg>;
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import type { Directive } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { popup } from '@/os.js';
|
||||
import { isTouchUsing } from '@/utility/touch.js';
|
||||
|
||||
export class UserPreview {
|
||||
private el;
|
||||
private user;
|
||||
private showTimer;
|
||||
private hideTimer;
|
||||
private checkTimer;
|
||||
private promise;
|
||||
private el: HTMLElement;
|
||||
private user: string | Misskey.entities.UserDetailed;
|
||||
private showTimer: number | null = null;
|
||||
private hideTimer: number | null = null;
|
||||
private checkTimer: number | null = null;
|
||||
private promise: null | { cancel: () => void } = null;
|
||||
|
||||
constructor(el, user) {
|
||||
constructor(el: HTMLElement, user: string | Misskey.entities.UserDetailed) {
|
||||
this.el = el;
|
||||
this.user = user;
|
||||
|
||||
@@ -43,10 +44,10 @@ export class UserPreview {
|
||||
source: this.el,
|
||||
}, {
|
||||
mouseover: () => {
|
||||
window.clearTimeout(this.hideTimer);
|
||||
if (this.hideTimer) window.clearTimeout(this.hideTimer);
|
||||
},
|
||||
mouseleave: () => {
|
||||
window.clearTimeout(this.showTimer);
|
||||
if (this.showTimer) window.clearTimeout(this.showTimer);
|
||||
this.hideTimer = window.setTimeout(this.close, 500);
|
||||
},
|
||||
closed: () => dispose(),
|
||||
@@ -60,8 +61,8 @@ export class UserPreview {
|
||||
|
||||
this.checkTimer = window.setInterval(() => {
|
||||
if (!window.document.body.contains(this.el)) {
|
||||
window.clearTimeout(this.showTimer);
|
||||
window.clearTimeout(this.hideTimer);
|
||||
if (this.showTimer) window.clearTimeout(this.showTimer);
|
||||
if (this.hideTimer) window.clearTimeout(this.hideTimer);
|
||||
this.close();
|
||||
}
|
||||
}, 1000);
|
||||
@@ -69,26 +70,26 @@ export class UserPreview {
|
||||
|
||||
private close() {
|
||||
if (this.promise) {
|
||||
window.clearInterval(this.checkTimer);
|
||||
if (this.checkTimer) window.clearInterval(this.checkTimer);
|
||||
this.promise.cancel();
|
||||
this.promise = null;
|
||||
}
|
||||
}
|
||||
|
||||
private onMouseover() {
|
||||
window.clearTimeout(this.showTimer);
|
||||
window.clearTimeout(this.hideTimer);
|
||||
if (this.showTimer) window.clearTimeout(this.showTimer);
|
||||
if (this.hideTimer) window.clearTimeout(this.hideTimer);
|
||||
this.showTimer = window.setTimeout(this.show, 500);
|
||||
}
|
||||
|
||||
private onMouseleave() {
|
||||
window.clearTimeout(this.showTimer);
|
||||
window.clearTimeout(this.hideTimer);
|
||||
if (this.showTimer) window.clearTimeout(this.showTimer);
|
||||
if (this.hideTimer) window.clearTimeout(this.hideTimer);
|
||||
this.hideTimer = window.setTimeout(this.close, 500);
|
||||
}
|
||||
|
||||
private onClick() {
|
||||
window.clearTimeout(this.showTimer);
|
||||
if (this.showTimer) window.clearTimeout(this.showTimer);
|
||||
this.close();
|
||||
}
|
||||
|
||||
@@ -105,8 +106,14 @@ export class UserPreview {
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
mounted(el: HTMLElement, binding, vn) {
|
||||
interface UserPreviewDirectiveElement extends HTMLElement {
|
||||
_userPreviewDirective_?: {
|
||||
preview: UserPreview;
|
||||
};
|
||||
}
|
||||
|
||||
export const userPreviewDirective = {
|
||||
mounted(el, binding) {
|
||||
if (binding.value == null) return;
|
||||
if (isTouchUsing) return;
|
||||
|
||||
@@ -117,10 +124,11 @@ export default {
|
||||
self.preview = new UserPreview(el, binding.value);
|
||||
},
|
||||
|
||||
unmounted(el, binding, vn) {
|
||||
unmounted(el, binding) {
|
||||
if (binding.value == null) return;
|
||||
|
||||
const self = el._userPreviewDirective_;
|
||||
if (self == null) return;
|
||||
self.preview.detach();
|
||||
},
|
||||
} as Directive;
|
||||
} as Directive<UserPreviewDirectiveElement, string | Misskey.entities.UserDetailed>;
|
||||
|
||||
@@ -53,6 +53,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker>
|
||||
<div class="_panel" style="padding: 16px;">
|
||||
<MkSwitch v-model="showRoleBadgesOfRemoteUsers" @change="onChange_showRoleBadgesOfRemoteUsers">
|
||||
<template #label><SearchLabel>{{ i18n.ts.showRoleBadgesOfRemoteUsers }}</SearchLabel></template>
|
||||
<template #caption>{{ i18n.ts.turnOffToImprovePerformance }}</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
</SearchMarker>
|
||||
|
||||
<SearchMarker>
|
||||
<MkFolder :defaultOpen="true">
|
||||
<template #icon><SearchIcon><i class="ti ti-bolt"></i></SearchIcon></template>
|
||||
@@ -188,6 +197,7 @@ const enableIdenticonGeneration = ref(meta.enableIdenticonGeneration);
|
||||
const enableChartsForRemoteUser = ref(meta.enableChartsForRemoteUser);
|
||||
const enableStatsForFederatedInstances = ref(meta.enableStatsForFederatedInstances);
|
||||
const enableChartsForFederatedInstances = ref(meta.enableChartsForFederatedInstances);
|
||||
const showRoleBadgesOfRemoteUsers = ref(meta.showRoleBadgesOfRemoteUsers);
|
||||
|
||||
function onChange_enableServerMachineStats(value: boolean) {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
@@ -229,6 +239,14 @@ function onChange_enableChartsForFederatedInstances(value: boolean) {
|
||||
});
|
||||
}
|
||||
|
||||
function onChange_showRoleBadgesOfRemoteUsers(value: boolean) {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
showRoleBadgesOfRemoteUsers: value,
|
||||
}).then(() => {
|
||||
fetchInstance(true);
|
||||
});
|
||||
}
|
||||
|
||||
const fttForm = useForm({
|
||||
enableFanoutTimeline: meta.enableFanoutTimeline,
|
||||
enableFanoutTimelineDbFallback: meta.enableFanoutTimelineDbFallback,
|
||||
|
||||
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkFolder v-for="token in items" :key="token.id" :defaultOpen="true">
|
||||
<template #icon>
|
||||
<img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/>
|
||||
<i v-else class="ti ti-plug"/>
|
||||
<i v-else class="ti ti-plug"></i>
|
||||
</template>
|
||||
<template #label>{{ token.name }}</template>
|
||||
<template #caption>{{ token.description }}</template>
|
||||
@@ -86,6 +86,7 @@ definePage(() => ({
|
||||
|
||||
<style lang="scss" module>
|
||||
.appIcon {
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -368,23 +368,19 @@ onDeactivated(disposeBannerParallaxResizeObserver);
|
||||
|
||||
> .banner-container {
|
||||
position: relative;
|
||||
height: 250px;
|
||||
--bannerHeight: 250px;
|
||||
height: var(--bannerHeight);
|
||||
overflow: clip;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
|
||||
> .banner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 300%;
|
||||
background-size: 100% auto;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-color: #4c5e6d;
|
||||
background-repeat: repeat-y;
|
||||
background-position: center;
|
||||
will-change: transform;
|
||||
transform: translateY(-50%);
|
||||
background-position-x: center;
|
||||
background-position-y: 50%;
|
||||
will-change: background-position-y;
|
||||
}
|
||||
|
||||
> .fade {
|
||||
@@ -677,7 +673,8 @@ onDeactivated(disposeBannerParallaxResizeObserver);
|
||||
> .main {
|
||||
> .profile > .main {
|
||||
> .banner-container {
|
||||
height: 140px;
|
||||
--bannerHeight: 140px;
|
||||
height: var(--bannerHeight);
|
||||
|
||||
> .fade {
|
||||
display: none;
|
||||
@@ -763,10 +760,10 @@ onDeactivated(disposeBannerParallaxResizeObserver);
|
||||
|
||||
@keyframes bannerParallaxKeyframes {
|
||||
from {
|
||||
transform: translateY(-50%);
|
||||
background-position-y: 50%;
|
||||
}
|
||||
to {
|
||||
transform: translateY(-30%);
|
||||
background-position-y: calc(50% + var(--bannerHeight, 250px) / 3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -167,7 +167,7 @@ const columnsEl = useTemplateRef('columnsEl');
|
||||
const addColumn = async (ev) => {
|
||||
const { canceled, result: column } = await os.select({
|
||||
title: i18n.ts._deck.addColumn,
|
||||
items: columnTypes.map(column => ({
|
||||
items: columnTypes.filter(column => column !== 'chat' || $i == null || $i.policies.chatAvailability !== 'unavailable').map(column => ({
|
||||
value: column, label: i18n.ts._deck._columns[column],
|
||||
})),
|
||||
});
|
||||
|
||||
@@ -7,21 +7,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<XColumn :column="column" :isStacked="isStacked">
|
||||
<template #header><i class="ti ti-messages" style="margin-right: 8px;"></i>{{ column.name || i18n.ts._deck._columns.chat }}</template>
|
||||
|
||||
<div style="padding: 8px;">
|
||||
<MkChatHistories/>
|
||||
<div style="padding: 8px;" class="_gaps">
|
||||
<MkInfo v-if="$i.policies.chatAvailability === 'readonly'">{{ i18n.ts._chat.chatIsReadOnlyForThisAccountOrServer }}</MkInfo>
|
||||
<MkInfo v-else-if="$i.policies.chatAvailability === 'unavailable'" warn>{{ i18n.ts._chat.chatNotAvailableForThisAccountOrServer }}</MkInfo>
|
||||
<MkChatHistories v-if="$i.policies.chatAvailability !== 'unavailable'"/>
|
||||
</div>
|
||||
</XColumn>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
import { i18n } from '../../i18n.js';
|
||||
import XColumn from './column.vue';
|
||||
import type { Column } from '@/deck.js';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkChatHistories from '@/components/MkChatHistories.vue';
|
||||
|
||||
defineProps<{
|
||||
column: Column;
|
||||
isStacked: boolean;
|
||||
}>();
|
||||
|
||||
const $i = ensureSignin();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user