Merge branch 'develop' into img-max
This commit is contained in:
31
packages/frontend/src/components/MkChannelList.vue
Normal file
31
packages/frontend/src/components/MkChannelList.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<MkPagination :pagination="pagination">
|
||||
<template #empty>
|
||||
<div class="_fullinfo">
|
||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
||||
<div>{{ i18n.ts.notFound }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<MkChannelPreview v-for="item in items" :key="item.id" class="_margin" :channel="extractor(item)"/>
|
||||
</template>
|
||||
</MkPagination>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
pagination: Paging;
|
||||
noGap?: boolean;
|
||||
extractor?: (item: any) => any;
|
||||
}>(), {
|
||||
extractor: (item) => item,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@@ -82,6 +82,7 @@ export default defineComponent({
|
||||
omitted: null,
|
||||
ignoreOmit: false,
|
||||
defaultStore,
|
||||
i18n,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -439,7 +439,6 @@ defineExpose({
|
||||
|
||||
&.asDrawer {
|
||||
width: 100% !important;
|
||||
padding: 12px 0 max(env(safe-area-inset-bottom, 0px), 12px) 0;
|
||||
|
||||
> .emojis {
|
||||
::v-deep(section) {
|
||||
@@ -498,6 +497,10 @@ defineExpose({
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
|
||||
&:not(:focus):not(.filled) {
|
||||
margin-bottom: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
|
||||
&:not(.filled) {
|
||||
order: 1;
|
||||
z-index: 2;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
import { onMounted } from 'vue';
|
||||
import * as misskey from 'misskey-js';
|
||||
import VuePlyr from 'vue-plyr';
|
||||
import { ColdDeviceStorage } from '@/store';
|
||||
import { soundConfigStore } from '@/scripts/sound';
|
||||
import 'vue-plyr/dist/vue-plyr.css';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
@@ -44,11 +44,11 @@ const audioEl = $shallowRef<HTMLAudioElement | null>();
|
||||
let hide = $ref(true);
|
||||
|
||||
function volumechange() {
|
||||
if (audioEl) ColdDeviceStorage.set('mediaVolume', audioEl.volume);
|
||||
if (audioEl) soundConfigStore.set('mediaVolume', audioEl.volume);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (audioEl) audioEl.volume = ColdDeviceStorage.get('mediaVolume');
|
||||
if (audioEl) audioEl.volume = soundConfigStore.state.mediaVolume;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1124,16 +1124,16 @@ defineExpose({
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
|
||||
grid-auto-rows: 46px;
|
||||
grid-auto-rows: 40px;
|
||||
}
|
||||
|
||||
.footerRight {
|
||||
flex: 0.3;
|
||||
flex: 0;
|
||||
margin-left: auto;
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
|
||||
grid-auto-rows: 46px;
|
||||
grid-auto-rows: 40px;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
@@ -1198,13 +1198,21 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 330px) {
|
||||
@container (max-width: 350px) {
|
||||
.footer {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.footerLeft {
|
||||
grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
|
||||
}
|
||||
|
||||
.footerRight {
|
||||
grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
|
||||
}
|
||||
|
||||
.headerRight {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -83,7 +83,7 @@ const choseAd = (): Ad | null => {
|
||||
};
|
||||
|
||||
const chosen = ref(choseAd());
|
||||
const shouldHide = $ref($i && $i.policies.canHideAds && (props.specify == null));
|
||||
const shouldHide = $ref(!defaultStore.state.forceShowAds && $i && $i.policies.canHideAds && (props.specify == null));
|
||||
|
||||
function reduceFrequency(): void {
|
||||
if (chosen.value == null) return;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { getStaticImageUrl } from '@/scripts/media-proxy';
|
||||
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy';
|
||||
import { defaultStore } from '@/store';
|
||||
import { customEmojis } from '@/custom-emojis';
|
||||
|
||||
@@ -15,25 +15,38 @@ const props = defineProps<{
|
||||
noStyle?: boolean;
|
||||
host?: string | null;
|
||||
url?: string;
|
||||
useOriginalSize?: boolean;
|
||||
}>();
|
||||
|
||||
const customEmojiName = computed(() => (props.name[0] === ':' ? props.name.substr(1, props.name.length - 2) : props.name).replace('@.', ''));
|
||||
const isLocal = computed(() => !props.host && (customEmojiName.value.endsWith('@.') || !customEmojiName.value.includes('@')));
|
||||
|
||||
const rawUrl = computed(() => {
|
||||
if (props.url) {
|
||||
return props.url;
|
||||
}
|
||||
if (props.host == null && !customEmojiName.value.includes('@')) {
|
||||
if (isLocal.value) {
|
||||
return customEmojis.value.find(x => x.name === customEmojiName.value)?.url ?? null;
|
||||
}
|
||||
return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
|
||||
});
|
||||
|
||||
const url = computed(() =>
|
||||
defaultStore.reactiveState.disableShowingAnimatedImages.value && rawUrl.value
|
||||
? getStaticImageUrl(rawUrl.value)
|
||||
: rawUrl.value,
|
||||
);
|
||||
const url = computed(() => {
|
||||
if (rawUrl.value == null) return null;
|
||||
|
||||
const proxied =
|
||||
(rawUrl.value.startsWith('/emoji/') || (props.useOriginalSize && isLocal.value))
|
||||
? rawUrl.value
|
||||
: getProxiedImageUrl(
|
||||
rawUrl.value,
|
||||
props.useOriginalSize ? undefined : 'emoji',
|
||||
false,
|
||||
true,
|
||||
);
|
||||
return defaultStore.reactiveState.disableShowingAnimatedImages.value
|
||||
? getStaticImageUrl(proxied)
|
||||
: proxied;
|
||||
});
|
||||
|
||||
const alt = computed(() => `:${customEmojiName.value}:`);
|
||||
let errored = $ref(url.value == null);
|
||||
|
||||
@@ -51,6 +51,10 @@ export default defineComponent({
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
rootScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
@@ -65,7 +69,12 @@ export default defineComponent({
|
||||
|
||||
const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm;
|
||||
|
||||
const genEl = (ast: mfm.MfmNode[]) => ast.map((token): VNode | string | (VNode | string)[] => {
|
||||
/**
|
||||
* Gen Vue Elements from MFM AST
|
||||
* @param ast MFM AST
|
||||
* @param scale How times large the text is
|
||||
*/
|
||||
const genEl = (ast: mfm.MfmNode[], scale: number) => ast.map((token): VNode | string | (VNode | string)[] => {
|
||||
switch (token.type) {
|
||||
case 'text': {
|
||||
const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
|
||||
@@ -84,17 +93,17 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
case 'bold': {
|
||||
return [h('b', genEl(token.children))];
|
||||
return [h('b', genEl(token.children, scale))];
|
||||
}
|
||||
|
||||
case 'strike': {
|
||||
return [h('del', genEl(token.children))];
|
||||
return [h('del', genEl(token.children, scale))];
|
||||
}
|
||||
|
||||
case 'italic': {
|
||||
return h('i', {
|
||||
style: 'font-style: oblique;',
|
||||
}, genEl(token.children));
|
||||
}, genEl(token.children, scale));
|
||||
}
|
||||
|
||||
case 'fn': {
|
||||
@@ -155,17 +164,17 @@ export default defineComponent({
|
||||
case 'x2': {
|
||||
return h('span', {
|
||||
class: defaultStore.state.advancedMfm ? 'mfm-x2' : '',
|
||||
}, genEl(token.children));
|
||||
}, genEl(token.children, scale * 2));
|
||||
}
|
||||
case 'x3': {
|
||||
return h('span', {
|
||||
class: defaultStore.state.advancedMfm ? 'mfm-x3' : '',
|
||||
}, genEl(token.children));
|
||||
}, genEl(token.children, scale * 3));
|
||||
}
|
||||
case 'x4': {
|
||||
return h('span', {
|
||||
class: defaultStore.state.advancedMfm ? 'mfm-x4' : '',
|
||||
}, genEl(token.children));
|
||||
}, genEl(token.children, scale * 4));
|
||||
}
|
||||
case 'font': {
|
||||
const family =
|
||||
@@ -182,7 +191,7 @@ export default defineComponent({
|
||||
case 'blur': {
|
||||
return h('span', {
|
||||
class: '_mfm_blur_',
|
||||
}, genEl(token.children));
|
||||
}, genEl(token.children, scale));
|
||||
}
|
||||
case 'rainbow': {
|
||||
const speed = validTime(token.props.args.speed) ?? '1s';
|
||||
@@ -191,9 +200,9 @@ export default defineComponent({
|
||||
}
|
||||
case 'sparkle': {
|
||||
if (!useAnim) {
|
||||
return genEl(token.children);
|
||||
return genEl(token.children, scale);
|
||||
}
|
||||
return h(MkSparkle, {}, genEl(token.children));
|
||||
return h(MkSparkle, {}, genEl(token.children, scale));
|
||||
}
|
||||
case 'rotate': {
|
||||
const degrees = parseFloat(token.props.args.deg ?? '90');
|
||||
@@ -214,7 +223,8 @@ export default defineComponent({
|
||||
}
|
||||
const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5);
|
||||
const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5);
|
||||
style = `transform: scale(${x}, ${y});`;
|
||||
style = `transform: scale(${x}, ${y});`;
|
||||
scale = scale * Math.max(x, y);
|
||||
break;
|
||||
}
|
||||
case 'fg': {
|
||||
@@ -231,24 +241,24 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
if (style == null) {
|
||||
return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children), ']']);
|
||||
return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children, scale), ']']);
|
||||
} else {
|
||||
return h('span', {
|
||||
style: 'display: inline-block; ' + style,
|
||||
}, genEl(token.children));
|
||||
}, genEl(token.children, scale));
|
||||
}
|
||||
}
|
||||
|
||||
case 'small': {
|
||||
return [h('small', {
|
||||
style: 'opacity: 0.7;',
|
||||
}, genEl(token.children))];
|
||||
}, genEl(token.children, scale))];
|
||||
}
|
||||
|
||||
case 'center': {
|
||||
return [h('div', {
|
||||
style: 'text-align:center;',
|
||||
}, genEl(token.children))];
|
||||
}, genEl(token.children, scale))];
|
||||
}
|
||||
|
||||
case 'url': {
|
||||
@@ -264,7 +274,7 @@ export default defineComponent({
|
||||
key: Math.random(),
|
||||
url: token.props.url,
|
||||
rel: 'nofollow noopener',
|
||||
}, genEl(token.children))];
|
||||
}, genEl(token.children, scale))];
|
||||
}
|
||||
|
||||
case 'mention': {
|
||||
@@ -303,11 +313,11 @@ export default defineComponent({
|
||||
if (!this.nowrap) {
|
||||
return [h('div', {
|
||||
style: QUOTE_STYLE,
|
||||
}, genEl(token.children))];
|
||||
}, genEl(token.children, scale))];
|
||||
} else {
|
||||
return [h('span', {
|
||||
style: QUOTE_STYLE,
|
||||
}, genEl(token.children))];
|
||||
}, genEl(token.children, scale))];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,6 +329,7 @@ export default defineComponent({
|
||||
name: token.props.name,
|
||||
normal: this.plain,
|
||||
host: null,
|
||||
useOriginalSize: scale >= 2.5,
|
||||
})];
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
@@ -332,6 +343,7 @@ export default defineComponent({
|
||||
url: this.emojiUrls ? this.emojiUrls[token.props.name] : null,
|
||||
normal: this.plain,
|
||||
host: this.author.host,
|
||||
useOriginalSize: scale >= 2.5,
|
||||
})];
|
||||
}
|
||||
}
|
||||
@@ -360,7 +372,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
case 'plain': {
|
||||
return [h('span', genEl(token.children))];
|
||||
return [h('span', genEl(token.children, scale))];
|
||||
}
|
||||
|
||||
default: {
|
||||
@@ -373,6 +385,6 @@ export default defineComponent({
|
||||
}).flat(Infinity) as (VNode | string)[];
|
||||
|
||||
// Parse ast to DOM
|
||||
return h('span', genEl(ast));
|
||||
return h('span', genEl(ast, this.rootScale));
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user