Merge tag '13.11.2' into merge-upstream
This commit is contained in:
@@ -77,6 +77,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
|
||||
createdAt: '2016-12-28T22:49:51.000Z',
|
||||
description: 'I am a cool user!',
|
||||
ffVisibility: 'public',
|
||||
roles: [],
|
||||
fields: [
|
||||
{
|
||||
name: 'Website',
|
||||
|
@@ -398,6 +398,7 @@ function toStories(component: string): string {
|
||||
Promise.all([
|
||||
glob('src/components/global/*.vue'),
|
||||
glob('src/components/MkGalleryPostPreview.vue'),
|
||||
glob('src/pages/user/home.vue'),
|
||||
])
|
||||
.then((globs) => globs.flat())
|
||||
.then((components) => Promise.all(components.map((component) => {
|
||||
|
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;
|
||||
|
@@ -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;
|
||||
|
@@ -2,6 +2,23 @@
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :content-max="700">
|
||||
<div v-if="tab === 'search'">
|
||||
<div class="_gaps">
|
||||
<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search">
|
||||
<template #prefix><i class="ti ti-search"></i></template>
|
||||
</MkInput>
|
||||
<MkRadios v-model="searchType" @update:model-value="search()">
|
||||
<option value="nameAndDescription">{{ i18n.ts._channel.nameAndDescription }}</option>
|
||||
<option value="nameOnly">{{ i18n.ts._channel.nameOnly }}</option>
|
||||
</MkRadios>
|
||||
<MkButton large primary gradate rounded @click="search">{{ i18n.ts.search }}</MkButton>
|
||||
</div>
|
||||
|
||||
<MkFoldableSection v-if="channelPagination">
|
||||
<template #header>{{ i18n.ts.searchResult }}</template>
|
||||
<MkChannelList :key="key" :pagination="channelPagination"/>
|
||||
</MkFoldableSection>
|
||||
</div>
|
||||
<div v-if="tab === 'featured'">
|
||||
<MkPagination v-slot="{items}" :pagination="featuredPagination">
|
||||
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_margin" :channel="channel"/>
|
||||
@@ -28,17 +45,35 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, onMounted } from 'vue';
|
||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||
import MkChannelList from '@/components/MkChannelList.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkRadios from '@/components/MkRadios.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||
import { useRouter } from '@/router';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
let tab = $ref('featured');
|
||||
const props = defineProps<{
|
||||
query: string;
|
||||
type?: string;
|
||||
}>();
|
||||
|
||||
let key = $ref('');
|
||||
let tab = $ref('search');
|
||||
let searchQuery = $ref('');
|
||||
let searchType = $ref('nameAndDescription');
|
||||
let channelPagination = $ref();
|
||||
|
||||
onMounted(() => {
|
||||
searchQuery = props.query ?? '';
|
||||
searchType = props.type ?? 'nameAndDescription';
|
||||
});
|
||||
|
||||
const featuredPagination = {
|
||||
endpoint: 'channels/featured' as const,
|
||||
@@ -58,6 +93,25 @@ const ownedPagination = {
|
||||
limit: 10,
|
||||
};
|
||||
|
||||
async function search() {
|
||||
const query = searchQuery.toString().trim();
|
||||
|
||||
if (query == null || query === '') return;
|
||||
|
||||
const type = searchType.toString().trim();
|
||||
|
||||
channelPagination = {
|
||||
endpoint: 'channels/search',
|
||||
limit: 10,
|
||||
params: {
|
||||
query: searchQuery,
|
||||
type: type,
|
||||
},
|
||||
};
|
||||
|
||||
key = query + type;
|
||||
}
|
||||
|
||||
function create() {
|
||||
router.push('/channels/new');
|
||||
}
|
||||
@@ -69,6 +123,10 @@ const headerActions = $computed(() => [{
|
||||
}]);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
key: 'search',
|
||||
title: i18n.ts.search,
|
||||
icon: 'ti ti-search',
|
||||
}, {
|
||||
key: 'featured',
|
||||
title: i18n.ts._channel.featured,
|
||||
icon: 'ti ti-comet',
|
||||
|
@@ -66,7 +66,7 @@ const recentPostsPagination = {
|
||||
};
|
||||
const popularPostsPagination = {
|
||||
endpoint: 'gallery/featured' as const,
|
||||
limit: 5,
|
||||
noPaging: true,
|
||||
};
|
||||
const myPostsPagination = {
|
||||
endpoint: 'i/gallery/posts' as const,
|
||||
|
@@ -8,27 +8,29 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #default="{items}">
|
||||
<div v-for="token in items" :key="token.id" class="_panel bfomjevm">
|
||||
<img v-if="token.iconUrl" class="icon" :src="token.iconUrl" alt=""/>
|
||||
<div class="body">
|
||||
<div class="name">{{ token.name }}</div>
|
||||
<div class="description">{{ token.description }}</div>
|
||||
<MkKeyValue oneline>
|
||||
<template #key>{{ i18n.ts.installedDate }}</template>
|
||||
<template #value><MkTime :time="token.createdAt"/></template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue oneline>
|
||||
<template #key>{{ i18n.ts.lastUsedDate }}</template>
|
||||
<template #value><MkTime :time="token.lastUsedAt"/></template>
|
||||
</MkKeyValue>
|
||||
<details>
|
||||
<summary>{{ i18n.ts.details }}</summary>
|
||||
<ul>
|
||||
<li v-for="p in token.permission" :key="p">{{ i18n.t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</details>
|
||||
<div class="actions">
|
||||
<MkButton inline danger @click="revoke(token)"><i class="ti ti-trash"></i></MkButton>
|
||||
<div class="_gaps">
|
||||
<div v-for="token in items" :key="token.id" class="_panel bfomjevm">
|
||||
<img v-if="token.iconUrl" class="icon" :src="token.iconUrl" alt=""/>
|
||||
<div class="body">
|
||||
<div class="name">{{ token.name }}</div>
|
||||
<div class="description">{{ token.description }}</div>
|
||||
<MkKeyValue oneline>
|
||||
<template #key>{{ i18n.ts.installedDate }}</template>
|
||||
<template #value><MkTime :time="token.createdAt"/></template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue oneline>
|
||||
<template #key>{{ i18n.ts.lastUsedDate }}</template>
|
||||
<template #value><MkTime :time="token.lastUsedAt"/></template>
|
||||
</MkKeyValue>
|
||||
<details>
|
||||
<summary>{{ i18n.ts.details }}</summary>
|
||||
<ul>
|
||||
<li v-for="p in token.permission" :key="p">{{ i18n.t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</details>
|
||||
<div class="actions">
|
||||
<MkButton inline danger @click="revoke(token)"><i class="ti ti-trash"></i></MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,6 +53,7 @@ const list = ref<any>(null);
|
||||
const pagination = {
|
||||
endpoint: 'i/apps' as const,
|
||||
limit: 100,
|
||||
noPaging: true,
|
||||
params: {
|
||||
sort: '+lastUsedAt',
|
||||
},
|
||||
|
@@ -61,6 +61,7 @@
|
||||
<MkSwitch v-model="squareAvatars">{{ i18n.ts.squareAvatars }}</MkSwitch>
|
||||
<MkSwitch v-model="useSystemFont">{{ i18n.ts.useSystemFont }}</MkSwitch>
|
||||
<MkSwitch v-model="disableDrawer">{{ i18n.ts.disableDrawer }}</MkSwitch>
|
||||
<MkSwitch v-model="forceShowAds">{{ i18n.ts.forceShowAds }}</MkSwitch>
|
||||
</div>
|
||||
<div>
|
||||
<MkRadios v-model="emojiStyle">
|
||||
@@ -157,6 +158,7 @@ const advancedMfm = computed(defaultStore.makeGetterSetter('advancedMfm'));
|
||||
const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle'));
|
||||
const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer'));
|
||||
const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages'));
|
||||
const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds'));
|
||||
const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages'));
|
||||
const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab'));
|
||||
const nsfw = computed(defaultStore.makeGetterSetter('nsfw'));
|
||||
|
@@ -399,7 +399,7 @@ function menu(ev: MouseEvent, profileId: string) {
|
||||
icon: 'ti ti-device-floppy',
|
||||
action: () => save(profileId),
|
||||
}, null, {
|
||||
text: ts._preferencesBackups.delete,
|
||||
text: ts.delete,
|
||||
icon: 'ti ti-trash',
|
||||
action: () => deleteProfile(profileId),
|
||||
danger: true,
|
||||
|
@@ -7,18 +7,20 @@
|
||||
<FormSection>
|
||||
<MkPagination :pagination="pagination">
|
||||
<template #default="{items}">
|
||||
<FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit/${webhook.id}`" class="_margin">
|
||||
<template #icon>
|
||||
<i v-if="webhook.active === false" class="ti ti-player-pause"></i>
|
||||
<i v-else-if="webhook.latestStatus === null" class="ti ti-circle"></i>
|
||||
<i v-else-if="[200, 201, 204].includes(webhook.latestStatus)" class="ti ti-check" :style="{ color: 'var(--success)' }"></i>
|
||||
<i v-else class="ti ti-alert-triangle" :style="{ color: 'var(--error)' }"></i>
|
||||
</template>
|
||||
{{ webhook.name || webhook.url }}
|
||||
<template #suffix>
|
||||
<MkTime v-if="webhook.latestSentAt" :time="webhook.latestSentAt"></MkTime>
|
||||
</template>
|
||||
</FormLink>
|
||||
<div class="_gaps">
|
||||
<FormLink v-for="webhook in items" :key="webhook.id" :to="`/settings/webhook/edit/${webhook.id}`">
|
||||
<template #icon>
|
||||
<i v-if="webhook.active === false" class="ti ti-player-pause"></i>
|
||||
<i v-else-if="webhook.latestStatus === null" class="ti ti-circle"></i>
|
||||
<i v-else-if="[200, 201, 204].includes(webhook.latestStatus)" class="ti ti-check" :style="{ color: 'var(--success)' }"></i>
|
||||
<i v-else class="ti ti-alert-triangle" :style="{ color: 'var(--error)' }"></i>
|
||||
</template>
|
||||
{{ webhook.name || webhook.url }}
|
||||
<template #suffix>
|
||||
<MkTime v-if="webhook.latestSentAt" :time="webhook.latestSentAt"></MkTime>
|
||||
</template>
|
||||
</FormLink>
|
||||
</div>
|
||||
</template>
|
||||
</MkPagination>
|
||||
</FormSection>
|
||||
@@ -35,7 +37,8 @@ import { i18n } from '@/i18n';
|
||||
|
||||
const pagination = {
|
||||
endpoint: 'i/webhooks/list' as const,
|
||||
limit: 10,
|
||||
limit: 100,
|
||||
noPaging: true,
|
||||
};
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
74
packages/frontend/src/pages/user/home.stories.impl.ts
Normal file
74
packages/frontend/src/pages/user/home.stories.impl.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import { StoryObj } from '@storybook/vue3';
|
||||
import { rest } from 'msw';
|
||||
import { userDetailed } from '../../../.storybook/fakes';
|
||||
import { commonHandlers } from '../../../.storybook/mocks';
|
||||
import home_ from './home.vue';
|
||||
export const Default = {
|
||||
render(args) {
|
||||
return {
|
||||
components: {
|
||||
home_,
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
args,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
props() {
|
||||
return {
|
||||
...this.args,
|
||||
};
|
||||
},
|
||||
},
|
||||
template: '<home_ v-bind="props" />',
|
||||
};
|
||||
},
|
||||
args: {
|
||||
user: userDetailed(),
|
||||
disableNotes: false,
|
||||
},
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
msw: {
|
||||
handlers: [
|
||||
...commonHandlers,
|
||||
rest.post('/api/users/notes', (req, res, ctx) => {
|
||||
return res(ctx.json([]));
|
||||
}),
|
||||
rest.get('/api/charts/user/notes', (req, res, ctx) => {
|
||||
const length = Math.max(Math.min(parseInt(req.url.searchParams.get('limit') ?? '30', 10), 1), 300);
|
||||
return res(ctx.json({
|
||||
total: Array.from({ length }, () => 0),
|
||||
inc: Array.from({ length }, () => 0),
|
||||
dec: Array.from({ length }, () => 0),
|
||||
diffs: {
|
||||
normal: Array.from({ length }, () => 0),
|
||||
reply: Array.from({ length }, () => 0),
|
||||
renote: Array.from({ length }, () => 0),
|
||||
withFile: Array.from({ length }, () => 0),
|
||||
},
|
||||
}));
|
||||
}),
|
||||
rest.get('/api/charts/user/pv', (req, res, ctx) => {
|
||||
const length = Math.max(Math.min(parseInt(req.url.searchParams.get('limit') ?? '30', 10), 1), 300);
|
||||
return res(ctx.json({
|
||||
upv: {
|
||||
user: Array.from({ length }, () => 0),
|
||||
visitor: Array.from({ length }, () => 0),
|
||||
},
|
||||
pv: {
|
||||
user: Array.from({ length }, () => 0),
|
||||
visitor: Array.from({ length }, () => 0),
|
||||
},
|
||||
}));
|
||||
}),
|
||||
],
|
||||
},
|
||||
chromatic: {
|
||||
// `XActivity` is not compatible with Chromatic for now
|
||||
disableSnapshot: true,
|
||||
},
|
||||
},
|
||||
} satisfies StoryObj<typeof home_>;
|
@@ -298,6 +298,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||
where: 'device',
|
||||
default: false,
|
||||
},
|
||||
forceShowAds: {
|
||||
where: 'device',
|
||||
default: false,
|
||||
},
|
||||
aiChanMode: {
|
||||
where: 'device',
|
||||
default: false,
|
||||
|
@@ -1,17 +1,18 @@
|
||||
import { post } from '@/os';
|
||||
import { api, post } from '@/os';
|
||||
import { $i, login } from '@/account';
|
||||
import { getAccountFromId } from '@/scripts/get-account-from-id';
|
||||
import { mainRouter } from '@/router';
|
||||
import { deepClone } from '@/scripts/clone';
|
||||
|
||||
export function swInject() {
|
||||
navigator.serviceWorker.addEventListener('message', ev => {
|
||||
navigator.serviceWorker.addEventListener('message', async ev => {
|
||||
if (_DEV_) {
|
||||
console.log('sw msg', ev.data);
|
||||
}
|
||||
|
||||
if (ev.data.type !== 'order') return;
|
||||
|
||||
if (ev.data.loginId !== $i?.id) {
|
||||
if (ev.data.loginId && ev.data.loginId !== $i?.id) {
|
||||
return getAccountFromId(ev.data.loginId).then(account => {
|
||||
if (!account) return;
|
||||
return login(account.token, ev.data.url);
|
||||
@@ -19,8 +20,18 @@ export function swInject() {
|
||||
}
|
||||
|
||||
switch (ev.data.order) {
|
||||
case 'post':
|
||||
return post(ev.data.options);
|
||||
case 'post': {
|
||||
const props = deepClone(ev.data.options);
|
||||
// プッシュ通知から来たreply,renoteはtruncateBodyが通されているため、
|
||||
// 完全なノートを取得しなおす
|
||||
if (props.reply) {
|
||||
props.reply = await api('notes/show', { noteId: props.reply.id });
|
||||
}
|
||||
if (props.renote) {
|
||||
props.renote = await api('notes/show', { noteId: props.renote.id });
|
||||
}
|
||||
return post(props);
|
||||
}
|
||||
case 'push':
|
||||
if (mainRouter.currentRoute.value.path === ev.data.url) {
|
||||
return window.scroll({ top: 0, behavior: 'smooth' });
|
||||
|
@@ -250,6 +250,7 @@ onMounted(() => {
|
||||
> .widgets {
|
||||
//--panelBorder: none;
|
||||
width: 300px;
|
||||
padding-bottom: calc(var(--margin) + env(safe-area-inset-bottom, 0px));
|
||||
|
||||
@media (max-width: $widgets-hide-threshold) {
|
||||
display: none;
|
||||
@@ -304,7 +305,7 @@ onMounted(() => {
|
||||
right: 0;
|
||||
z-index: 1001;
|
||||
height: 100dvh;
|
||||
padding: var(--margin);
|
||||
padding: var(--margin) var(--margin) calc(var(--margin) + env(safe-area-inset-bottom, 0px));
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
background: var(--bg);
|
||||
|
@@ -296,7 +296,7 @@ $widgets-hide-threshold: 1090px;
|
||||
}
|
||||
|
||||
.widgets {
|
||||
padding: 0 var(--margin);
|
||||
padding: 0 var(--margin) calc(var(--margin) + env(safe-area-inset-bottom, 0px));
|
||||
border-left: solid 0.5px var(--divider);
|
||||
background: var(--bg);
|
||||
|
||||
@@ -329,7 +329,7 @@ $widgets-hide-threshold: 1090px;
|
||||
right: 0;
|
||||
z-index: 1001;
|
||||
height: 100dvh;
|
||||
padding: var(--margin) !important;
|
||||
padding: var(--margin) var(--margin) calc(var(--margin) + env(safe-area-inset-bottom, 0px)) !important;
|
||||
box-sizing: border-box;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<XWidgets :class="$style.widgets" :edit="editMode" :widgets="widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
|
||||
|
||||
<button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button>
|
||||
<button v-else class="_textButton mk-widget-edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button>
|
||||
<button v-else class="_textButton mk-widget-edit" :class="$style.edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -91,4 +91,8 @@ function updateWidgets(thisWidgets) {
|
||||
.widgets {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.edit {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user