デッキまわりをCompositon API / Setup Sugarに (#8410)
* universal.widgets.vue * column.vue, antenna-column.vue * direct-column.vue, list-column.vue * main-column.vue * wip * ✌️ * fix * ✌️ * ✌️
This commit is contained in:
parent
eb9e6d230f
commit
78736c70f7
|
@ -17,7 +17,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineComponent, PropType, markRaw, onUnmounted, onMounted, computed, ref } from 'vue';
|
import { defineComponent, markRaw, onUnmounted, onMounted, computed, ref } from 'vue';
|
||||||
import { notificationTypes } from 'misskey-js';
|
import { notificationTypes } from 'misskey-js';
|
||||||
import MkPagination from '@/components/ui/pagination.vue';
|
import MkPagination from '@/components/ui/pagination.vue';
|
||||||
import { Paging } from '@/components/ui/pagination.vue';
|
import { Paging } from '@/components/ui/pagination.vue';
|
||||||
|
@ -29,7 +29,7 @@ import { stream } from '@/stream';
|
||||||
import { $i } from '@/account';
|
import { $i } from '@/account';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
includeTypes?: PropType<typeof notificationTypes[number][]>;
|
includeTypes?: typeof notificationTypes[number][];
|
||||||
unreadOnly?: boolean;
|
unreadOnly?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
|
@ -293,23 +293,25 @@ export function inputDate(props: {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function select(props: {
|
export function select<C extends any = any>(props: {
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
default?: string | null;
|
default?: string | null;
|
||||||
items?: {
|
} & ({
|
||||||
value: string;
|
items: {
|
||||||
|
value: C;
|
||||||
text: string;
|
text: string;
|
||||||
}[];
|
}[];
|
||||||
groupedItems?: {
|
} | {
|
||||||
|
groupedItems: {
|
||||||
label: string;
|
label: string;
|
||||||
items: {
|
items: {
|
||||||
value: string;
|
value: C;
|
||||||
text: string;
|
text: string;
|
||||||
}[];
|
}[];
|
||||||
}[];
|
}[];
|
||||||
}): Promise<{ canceled: true; result: undefined; } | {
|
})): Promise<{ canceled: true; result: undefined; } | {
|
||||||
canceled: false; result: string;
|
canceled: false; result: C;
|
||||||
}> {
|
}> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(import('@/components/dialog.vue'), {
|
popup(import('@/components/dialog.vue'), {
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
:key="ids[0]"
|
:key="ids[0]"
|
||||||
class="column"
|
class="column"
|
||||||
:column="columns.find(c => c.id === ids[0])"
|
:column="columns.find(c => c.id === ids[0])"
|
||||||
:style="columns.find(c => c.id === ids[0]).flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0]).width + 'px' }"
|
:is-stacked="false"
|
||||||
|
:style="columns.find(c => c.id === ids[0])!.flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0])!.width + 'px' }"
|
||||||
@parent-focus="moveFocus(ids[0], $event)"
|
@parent-focus="moveFocus(ids[0], $event)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -25,8 +26,8 @@
|
||||||
<div v-if="isMobile" class="buttons">
|
<div v-if="isMobile" class="buttons">
|
||||||
<button class="button nav _button" @click="drawerMenuShowing = true"><i class="fas fa-bars"></i><span v-if="menuIndicated" class="indicator"><i class="fas fa-circle"></i></span></button>
|
<button class="button nav _button" @click="drawerMenuShowing = true"><i class="fas fa-bars"></i><span v-if="menuIndicated" class="indicator"><i class="fas fa-circle"></i></span></button>
|
||||||
<button class="button home _button" @click="$router.push('/')"><i class="fas fa-home"></i></button>
|
<button class="button home _button" @click="$router.push('/')"><i class="fas fa-home"></i></button>
|
||||||
<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button>
|
<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i?.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button>
|
||||||
<button class="button post _button" @click="post()"><i class="fas fa-pencil-alt"></i></button>
|
<button class="button post _button" @click="os.post()"><i class="fas fa-pencil-alt"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition :name="$store.state.animation ? 'menu-back' : ''">
|
<transition :name="$store.state.animation ? 'menu-back' : ''">
|
||||||
|
@ -45,8 +46,8 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, provide, ref, watch } from 'vue';
|
import { computed, provide, ref, watch } from 'vue';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import DeckColumnCore from '@/ui/deck/column-core.vue';
|
import DeckColumnCore from '@/ui/deck/column-core.vue';
|
||||||
import XSidebar from '@/ui/_common_/sidebar.vue';
|
import XSidebar from '@/ui/_common_/sidebar.vue';
|
||||||
|
@ -60,38 +61,29 @@ import { useRoute } from 'vue-router';
|
||||||
import { $i } from '@/account';
|
import { $i } from '@/account';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
const isMobile = ref(window.innerWidth <= 500);
|
||||||
components: {
|
window.addEventListener('resize', () => {
|
||||||
XCommon,
|
|
||||||
XSidebar,
|
|
||||||
XDrawerMenu,
|
|
||||||
DeckColumnCore,
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const isMobile = ref(window.innerWidth <= 500);
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
isMobile.value = window.innerWidth <= 500;
|
isMobile.value = window.innerWidth <= 500;
|
||||||
});
|
});
|
||||||
|
|
||||||
const drawerMenuShowing = ref(false);
|
const drawerMenuShowing = ref(false);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
drawerMenuShowing.value = false;
|
drawerMenuShowing.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = deckStore.reactiveState.columns;
|
const columns = deckStore.reactiveState.columns;
|
||||||
const layout = deckStore.reactiveState.layout;
|
const layout = deckStore.reactiveState.layout;
|
||||||
const menuIndicated = computed(() => {
|
const menuIndicated = computed(() => {
|
||||||
if ($i == null) return false;
|
if ($i == null) return false;
|
||||||
for (const def in menuDef) {
|
for (const def in menuDef) {
|
||||||
if (menuDef[def].indicated) return true;
|
if (menuDef[def].indicated) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const addColumn = async (ev) => {
|
const addColumn = async (ev) => {
|
||||||
const columns = [
|
const columns = [
|
||||||
'main',
|
'main',
|
||||||
'widgets',
|
'widgets',
|
||||||
|
@ -117,45 +109,34 @@ export default defineComponent({
|
||||||
name: i18n.t('_deck._columns.' + column),
|
name: i18n.t('_deck._columns.' + column),
|
||||||
width: 330,
|
width: 330,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onContextmenu = (ev) => {
|
const onContextmenu = (ev) => {
|
||||||
os.contextMenu([{
|
os.contextMenu([{
|
||||||
text: i18n.ts._deck.addColumn,
|
text: i18n.ts._deck.addColumn,
|
||||||
icon: null,
|
action: addColumn,
|
||||||
action: addColumn
|
|
||||||
}], ev);
|
}], ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
provide('shouldSpacerMin', true);
|
provide('shouldSpacerMin', true);
|
||||||
if (deckStore.state.navWindow) {
|
if (deckStore.state.navWindow) {
|
||||||
provide('navHook', (url) => {
|
provide('navHook', (url) => {
|
||||||
os.pageWindow(url);
|
os.pageWindow(url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.documentElement.style.overflowY = 'hidden';
|
document.documentElement.style.overflowY = 'hidden';
|
||||||
document.documentElement.style.scrollBehavior = 'auto';
|
document.documentElement.style.scrollBehavior = 'auto';
|
||||||
window.addEventListener('wheel', (ev) => {
|
window.addEventListener('wheel', (ev) => {
|
||||||
if (getScrollContainer(ev.target) == null) {
|
if (getScrollContainer(ev.target as HTMLElement) == null) {
|
||||||
document.documentElement.scrollLeft += ev.deltaY > 0 ? 96 : -96;
|
document.documentElement.scrollLeft += ev.deltaY > 0 ? 96 : -96;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
loadDeck();
|
|
||||||
|
|
||||||
return {
|
|
||||||
isMobile,
|
|
||||||
deckStore,
|
|
||||||
drawerMenuShowing,
|
|
||||||
columns,
|
|
||||||
layout,
|
|
||||||
menuIndicated,
|
|
||||||
onContextmenu,
|
|
||||||
wallpaper: localStorage.getItem('wallpaper') != null,
|
|
||||||
post: os.post,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
loadDeck();
|
||||||
|
|
||||||
|
function moveFocus(id: string, direction: 'up' | 'down' | 'left' | 'right') {
|
||||||
|
// TODO??
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,75 +1,62 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :func="{ handler: setAntenna, title: $ts.selectAntenna }" :column="column" :is-stacked="isStacked">
|
<XColumn :func="{ handler: setAntenna, title: $ts.selectAntenna }" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header>
|
<template #header>
|
||||||
<i class="fas fa-satellite"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
<i class="fas fa-satellite"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<XTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @after="() => $emit('loaded')"/>
|
<XTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @after="() => emit('loaded')"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XTimeline from '@/components/timeline.vue';
|
import XTimeline from '@/components/timeline.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { updateColumn } from './deck-store';
|
import { updateColumn, Column } from './deck-store';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
components: {
|
column: Column;
|
||||||
XColumn,
|
isStacked: boolean;
|
||||||
XTimeline,
|
}>();
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const emit = defineEmits<{
|
||||||
column: {
|
(e: 'loaded'): void;
|
||||||
type: Object,
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
required: true
|
}>();
|
||||||
},
|
|
||||||
isStacked: {
|
let timeline = $ref<InstanceType<typeof XTimeline>>();
|
||||||
type: Boolean,
|
|
||||||
required: true
|
onMounted(() => {
|
||||||
|
if (props.column.antennaId == null) {
|
||||||
|
setAntenna();
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
|
|
||||||
data() {
|
async function setAntenna() {
|
||||||
return {
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
mediaOnly() {
|
|
||||||
(this.$refs.timeline as any).reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
if (this.column.antennaId == null) {
|
|
||||||
this.setAntenna();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async setAntenna() {
|
|
||||||
const antennas = await os.api('antennas/list');
|
const antennas = await os.api('antennas/list');
|
||||||
const { canceled, result: antenna } = await os.select({
|
const { canceled, result: antenna } = await os.select({
|
||||||
title: this.$ts.selectAntenna,
|
title: i18n.ts.selectAntenna,
|
||||||
items: antennas.map(x => ({
|
items: antennas.map(x => ({
|
||||||
value: x, text: x.name
|
value: x, text: x.name
|
||||||
})),
|
})),
|
||||||
default: this.column.antennaId
|
default: props.column.antennaId
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
updateColumn(this.column.id, {
|
updateColumn(props.column.id, {
|
||||||
antennaId: antenna.id
|
antennaId: antenna.id
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
/*
|
||||||
|
function focus() {
|
||||||
|
timeline.focus();
|
||||||
|
}
|
||||||
|
|
||||||
focus() {
|
defineExpose({
|
||||||
(this.$refs.timeline as any).focus();
|
focus,
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- TODO: リファクタの余地がありそう -->
|
<!-- TODO: リファクタの余地がありそう -->
|
||||||
<XMainColumn v-if="column.type === 'main'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<div v-if="!column">たぶん見えちゃいけないやつ</div>
|
||||||
<XWidgetsColumn v-else-if="column.type === 'widgets'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XMainColumn v-else-if="column.type === 'main'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
<XNotificationsColumn v-else-if="column.type === 'notifications'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XWidgetsColumn v-else-if="column.type === 'widgets'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
<XTlColumn v-else-if="column.type === 'tl'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XNotificationsColumn v-else-if="column.type === 'notifications'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
<XListColumn v-else-if="column.type === 'list'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XTlColumn v-else-if="column.type === 'tl'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
<XAntennaColumn v-else-if="column.type === 'antenna'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XListColumn v-else-if="column.type === 'list'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
<XMentionsColumn v-else-if="column.type === 'mentions'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XAntennaColumn v-else-if="column.type === 'antenna'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
<XDirectColumn v-else-if="column.type === 'direct'" :column="column" :is-stacked="isStacked" @parent-focus="$emit('parent-focus', $event)"/>
|
<XMentionsColumn v-else-if="column.type === 'mentions'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
|
<XDirectColumn v-else-if="column.type === 'direct'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { } from 'vue';
|
||||||
import XMainColumn from './main-column.vue';
|
import XMainColumn from './main-column.vue';
|
||||||
import XTlColumn from './tl-column.vue';
|
import XTlColumn from './tl-column.vue';
|
||||||
import XAntennaColumn from './antenna-column.vue';
|
import XAntennaColumn from './antenna-column.vue';
|
||||||
|
@ -20,33 +21,24 @@ import XNotificationsColumn from './notifications-column.vue';
|
||||||
import XWidgetsColumn from './widgets-column.vue';
|
import XWidgetsColumn from './widgets-column.vue';
|
||||||
import XMentionsColumn from './mentions-column.vue';
|
import XMentionsColumn from './mentions-column.vue';
|
||||||
import XDirectColumn from './direct-column.vue';
|
import XDirectColumn from './direct-column.vue';
|
||||||
|
import { Column } from './deck-store';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
column?: Column;
|
||||||
|
isStacked: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
/*
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
|
||||||
XMainColumn,
|
|
||||||
XTlColumn,
|
|
||||||
XAntennaColumn,
|
|
||||||
XListColumn,
|
|
||||||
XNotificationsColumn,
|
|
||||||
XWidgetsColumn,
|
|
||||||
XMentionsColumn,
|
|
||||||
XDirectColumn
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
column: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
isStacked: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
focus() {
|
focus() {
|
||||||
this.$children[0].focus();
|
this.$children[0].focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -31,211 +31,186 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
export type DeckFunc = {
|
||||||
|
title: string;
|
||||||
|
handler: (payload: MouseEvent) => void;
|
||||||
|
icon?: string;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onBeforeUnmount, onMounted, provide, watch } from 'vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store';
|
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn, Column } from './deck-store';
|
||||||
import { deckStore } from './deck-store';
|
import { deckStore } from './deck-store';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
provide('shouldHeaderThin', true);
|
||||||
provide: {
|
provide('shouldOmitHeaderTitle', true);
|
||||||
shouldHeaderThin: true,
|
|
||||||
shouldOmitHeaderTitle: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const props = withDefaults(defineProps<{
|
||||||
column: {
|
column: Column;
|
||||||
type: Object,
|
isStacked?: boolean;
|
||||||
required: false,
|
func?: DeckFunc | null;
|
||||||
default: null
|
naked?: boolean;
|
||||||
},
|
indicated?: boolean;
|
||||||
isStacked: {
|
}>(), {
|
||||||
type: Boolean,
|
isStacked: false,
|
||||||
required: false,
|
func: null,
|
||||||
default: false
|
naked: false,
|
||||||
},
|
indicated: false,
|
||||||
func: {
|
});
|
||||||
type: Object,
|
|
||||||
required: false,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
naked: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
indicated: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
const emit = defineEmits<{
|
||||||
return {
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
deckStore,
|
(e: 'change-active-state', v: boolean): void;
|
||||||
dragging: false,
|
}>();
|
||||||
draghover: false,
|
|
||||||
dropready: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
let body = $ref<HTMLDivElement>();
|
||||||
isMainColumn(): boolean {
|
|
||||||
return this.column.type === 'main';
|
|
||||||
},
|
|
||||||
|
|
||||||
active(): boolean {
|
let dragging = $ref(false);
|
||||||
return this.column.active !== false;
|
watch($$(dragging), v => os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd'));
|
||||||
},
|
|
||||||
|
|
||||||
keymap(): any {
|
let draghover = $ref(false);
|
||||||
return {
|
let dropready = $ref(false);
|
||||||
'shift+up': () => this.$parent.$emit('parent-focus', 'up'),
|
|
||||||
'shift+down': () => this.$parent.$emit('parent-focus', 'down'),
|
|
||||||
'shift+left': () => this.$parent.$emit('parent-focus', 'left'),
|
|
||||||
'shift+right': () => this.$parent.$emit('parent-focus', 'right'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
const isMainColumn = $computed(() => props.column.type === 'main');
|
||||||
active(v) {
|
const active = $computed(() => props.column.active !== false);
|
||||||
this.$emit('change-active-state', v);
|
watch($$(active), v => emit('change-active-state', v));
|
||||||
},
|
|
||||||
|
|
||||||
dragging(v) {
|
const keymap = $computed(() => ({
|
||||||
os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd');
|
'shift+up': () => emit('parent-focus', 'up'),
|
||||||
}
|
'shift+down': () => emit('parent-focus', 'down'),
|
||||||
},
|
'shift+left': () => emit('parent-focus', 'left'),
|
||||||
|
'shift+right': () => emit('parent-focus', 'right'),
|
||||||
|
}));
|
||||||
|
|
||||||
mounted() {
|
onMounted(() => {
|
||||||
os.deckGlobalEvents.on('column.dragStart', this.onOtherDragStart);
|
os.deckGlobalEvents.on('column.dragStart', onOtherDragStart);
|
||||||
os.deckGlobalEvents.on('column.dragEnd', this.onOtherDragEnd);
|
os.deckGlobalEvents.on('column.dragEnd', onOtherDragEnd);
|
||||||
},
|
});
|
||||||
|
|
||||||
beforeUnmount() {
|
onBeforeUnmount(() => {
|
||||||
os.deckGlobalEvents.off('column.dragStart', this.onOtherDragStart);
|
os.deckGlobalEvents.off('column.dragStart', onOtherDragStart);
|
||||||
os.deckGlobalEvents.off('column.dragEnd', this.onOtherDragEnd);
|
os.deckGlobalEvents.off('column.dragEnd', onOtherDragEnd);
|
||||||
},
|
});
|
||||||
|
|
||||||
methods: {
|
|
||||||
onOtherDragStart() {
|
|
||||||
this.dropready = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
onOtherDragEnd() {
|
function onOtherDragStart() {
|
||||||
this.dropready = false;
|
dropready = true;
|
||||||
},
|
}
|
||||||
|
|
||||||
toggleActive() {
|
function onOtherDragEnd() {
|
||||||
if (!this.isStacked) return;
|
dropready = false;
|
||||||
updateColumn(this.column.id, {
|
}
|
||||||
active: !this.column.active
|
|
||||||
|
function toggleActive() {
|
||||||
|
if (!props.isStacked) return;
|
||||||
|
updateColumn(props.column.id, {
|
||||||
|
active: !props.column.active
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
getMenu() {
|
function getMenu() {
|
||||||
const items = [{
|
const items = [{
|
||||||
icon: 'fas fa-pencil-alt',
|
icon: 'fas fa-pencil-alt',
|
||||||
text: this.$ts.edit,
|
text: i18n.ts.edit,
|
||||||
action: async () => {
|
action: async () => {
|
||||||
const { canceled, result } = await os.form(this.column.name, {
|
const { canceled, result } = await os.form(props.column.name, {
|
||||||
name: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
label: this.$ts.name,
|
label: i18n.ts.name,
|
||||||
default: this.column.name
|
default: props.column.name
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
label: this.$ts.width,
|
label: i18n.ts.width,
|
||||||
default: this.column.width
|
default: props.column.width
|
||||||
},
|
},
|
||||||
flexible: {
|
flexible: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
label: this.$ts.flexible,
|
label: i18n.ts.flexible,
|
||||||
default: this.column.flexible
|
default: props.column.flexible
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
updateColumn(this.column.id, result);
|
updateColumn(props.column.id, result);
|
||||||
}
|
}
|
||||||
}, null, {
|
}, null, {
|
||||||
icon: 'fas fa-arrow-left',
|
icon: 'fas fa-arrow-left',
|
||||||
text: this.$ts._deck.swapLeft,
|
text: i18n.ts._deck.swapLeft,
|
||||||
action: () => {
|
action: () => {
|
||||||
swapLeftColumn(this.column.id);
|
swapLeftColumn(props.column.id);
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
icon: 'fas fa-arrow-right',
|
icon: 'fas fa-arrow-right',
|
||||||
text: this.$ts._deck.swapRight,
|
text: i18n.ts._deck.swapRight,
|
||||||
action: () => {
|
action: () => {
|
||||||
swapRightColumn(this.column.id);
|
swapRightColumn(props.column.id);
|
||||||
}
|
}
|
||||||
}, this.isStacked ? {
|
}, props.isStacked ? {
|
||||||
icon: 'fas fa-arrow-up',
|
icon: 'fas fa-arrow-up',
|
||||||
text: this.$ts._deck.swapUp,
|
text: i18n.ts._deck.swapUp,
|
||||||
action: () => {
|
action: () => {
|
||||||
swapUpColumn(this.column.id);
|
swapUpColumn(props.column.id);
|
||||||
}
|
}
|
||||||
} : undefined, this.isStacked ? {
|
} : undefined, props.isStacked ? {
|
||||||
icon: 'fas fa-arrow-down',
|
icon: 'fas fa-arrow-down',
|
||||||
text: this.$ts._deck.swapDown,
|
text: i18n.ts._deck.swapDown,
|
||||||
action: () => {
|
action: () => {
|
||||||
swapDownColumn(this.column.id);
|
swapDownColumn(props.column.id);
|
||||||
}
|
}
|
||||||
} : undefined, null, {
|
} : undefined, null, {
|
||||||
icon: 'fas fa-window-restore',
|
icon: 'fas fa-window-restore',
|
||||||
text: this.$ts._deck.stackLeft,
|
text: i18n.ts._deck.stackLeft,
|
||||||
action: () => {
|
action: () => {
|
||||||
stackLeftColumn(this.column.id);
|
stackLeftColumn(props.column.id);
|
||||||
}
|
}
|
||||||
}, this.isStacked ? {
|
}, props.isStacked ? {
|
||||||
icon: 'fas fa-window-maximize',
|
icon: 'fas fa-window-maximize',
|
||||||
text: this.$ts._deck.popRight,
|
text: i18n.ts._deck.popRight,
|
||||||
action: () => {
|
action: () => {
|
||||||
popRightColumn(this.column.id);
|
popRightColumn(props.column.id);
|
||||||
}
|
}
|
||||||
} : undefined, null, {
|
} : undefined, null, {
|
||||||
icon: 'fas fa-trash-alt',
|
icon: 'fas fa-trash-alt',
|
||||||
text: this.$ts.remove,
|
text: i18n.ts.remove,
|
||||||
danger: true,
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
removeColumn(this.column.id);
|
removeColumn(props.column.id);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
},
|
}
|
||||||
|
|
||||||
onContextmenu(ev: MouseEvent) {
|
function onContextmenu(ev: MouseEvent) {
|
||||||
os.contextMenu(this.getMenu(), ev);
|
os.contextMenu(getMenu(), ev);
|
||||||
},
|
}
|
||||||
|
|
||||||
goTop() {
|
function goTop() {
|
||||||
this.$refs.body.scrollTo({
|
body.scrollTo({
|
||||||
top: 0,
|
top: 0,
|
||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
onDragstart(e) {
|
function onDragstart(e) {
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
e.dataTransfer.setData(_DATA_TRANSFER_DECK_COLUMN_, this.column.id);
|
e.dataTransfer.setData(_DATA_TRANSFER_DECK_COLUMN_, props.column.id);
|
||||||
|
|
||||||
// Chromeのバグで、Dragstartハンドラ内ですぐにDOMを変更する(=リアクティブなプロパティを変更する)とDragが終了してしまう
|
// Chromeのバグで、Dragstartハンドラ内ですぐにDOMを変更する(=リアクティブなプロパティを変更する)とDragが終了してしまう
|
||||||
// SEE: https://stackoverflow.com/questions/19639969/html5-dragend-event-firing-immediately
|
// SEE: https://stackoverflow.com/questions/19639969/html5-dragend-event-firing-immediately
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
this.dragging = true;
|
dragging = true;
|
||||||
}, 10);
|
}, 10);
|
||||||
},
|
}
|
||||||
|
|
||||||
onDragend(e) {
|
function onDragend(e) {
|
||||||
this.dragging = false;
|
dragging = false;
|
||||||
},
|
}
|
||||||
|
|
||||||
onDragover(e) {
|
function onDragover(e) {
|
||||||
// 自分自身がドラッグされている場合
|
// 自分自身がドラッグされている場合
|
||||||
if (this.dragging) {
|
if (dragging) {
|
||||||
// 自分自身にはドロップさせない
|
// 自分自身にはドロップさせない
|
||||||
e.dataTransfer.dropEffect = 'none';
|
e.dataTransfer.dropEffect = 'none';
|
||||||
return;
|
return;
|
||||||
|
@ -245,24 +220,22 @@ export default defineComponent({
|
||||||
|
|
||||||
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||||
|
|
||||||
if (!this.dragging && isDeckColumn) this.draghover = true;
|
if (!dragging && isDeckColumn) draghover = true;
|
||||||
},
|
}
|
||||||
|
|
||||||
onDragleave() {
|
function onDragleave() {
|
||||||
this.draghover = false;
|
draghover = false;
|
||||||
},
|
}
|
||||||
|
|
||||||
onDrop(e) {
|
function onDrop(e) {
|
||||||
this.draghover = false;
|
draghover = false;
|
||||||
os.deckGlobalEvents.emit('column.dragEnd');
|
os.deckGlobalEvents.emit('column.dragEnd');
|
||||||
|
|
||||||
const id = e.dataTransfer.getData(_DATA_TRANSFER_DECK_COLUMN_);
|
const id = e.dataTransfer.getData(_DATA_TRANSFER_DECK_COLUMN_);
|
||||||
if (id != null && id != '') {
|
if (id != null && id != '') {
|
||||||
swapColumn(this.column.id, id);
|
swapColumn(props.column.id, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { throttle } from 'throttle-debounce';
|
import { throttle } from 'throttle-debounce';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { api } from '@/os';
|
import { api } from '@/os';
|
||||||
import { markRaw, watch } from 'vue';
|
import { markRaw } from 'vue';
|
||||||
import { Storage } from '../../pizzax';
|
import { Storage } from '../../pizzax';
|
||||||
|
import { notificationTypes } from 'misskey-js';
|
||||||
|
|
||||||
type ColumnWidget = {
|
type ColumnWidget = {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -10,13 +11,18 @@ type ColumnWidget = {
|
||||||
data: Record<string, any>;
|
data: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Column = {
|
export type Column = {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
width: number;
|
width: number;
|
||||||
widgets?: ColumnWidget[];
|
widgets?: ColumnWidget[];
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
flexible?: boolean;
|
||||||
|
antennaId?: string;
|
||||||
|
listId?: string;
|
||||||
|
includingTypes?: typeof notificationTypes[number][];
|
||||||
|
tl?: 'home' | 'local' | 'social' | 'global';
|
||||||
};
|
};
|
||||||
|
|
||||||
function copy<T>(x: T): T {
|
function copy<T>(x: T): T {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :column="column" :is-stacked="isStacked">
|
<XColumn :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header><i class="fas fa-envelope" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
<template #header><i class="fas fa-envelope" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
||||||
|
|
||||||
<XNotes :pagination="pagination"/>
|
<XNotes :pagination="pagination"/>
|
||||||
|
@ -7,21 +7,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as os from '@/os';
|
import { Column } from './deck-store';
|
||||||
|
|
||||||
const props = defineProps<{
|
defineProps<{
|
||||||
column: Record<string, unknown>; // TODO
|
column: Column;
|
||||||
isStacked: boolean;
|
isStacked: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const pagination = {
|
const pagination = {
|
||||||
point: 'notes/mentions' as const,
|
endpoint: 'notes/mentions' as const,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
params: computed(() => ({
|
params: {
|
||||||
visibility: 'specified' as const,
|
visibility: 'specified'
|
||||||
})),
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,75 +1,65 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :func="{ handler: setList, title: $ts.selectList }" :column="column" :is-stacked="isStacked">
|
<XColumn :func="{ handler: setList, title: $ts.selectList }" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header>
|
<template #header>
|
||||||
<i class="fas fa-list-ul"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
<i class="fas fa-list-ul"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<XTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" @after="() => $emit('loaded')"/>
|
<XTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" @after="() => emit('loaded')"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XTimeline from '@/components/timeline.vue';
|
import XTimeline from '@/components/timeline.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { updateColumn } from './deck-store';
|
import { updateColumn, Column } from './deck-store';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
column: Column;
|
||||||
|
isStacked: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'loaded'): void;
|
||||||
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
let timeline = $ref<InstanceType<typeof XTimeline>>();
|
||||||
|
|
||||||
|
if (props.column.listId == null) {
|
||||||
|
setList();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setList() {
|
||||||
|
const lists = await os.api('users/lists/list');
|
||||||
|
const { canceled, result: list } = await os.select({
|
||||||
|
title: i18n.ts.selectList,
|
||||||
|
items: lists.map(x => ({
|
||||||
|
value: x, text: x.name
|
||||||
|
})),
|
||||||
|
default: props.column.listId
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
updateColumn(props.column.id, {
|
||||||
|
listId: list.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function focus() {
|
||||||
|
timeline.focus();
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
|
||||||
XColumn,
|
|
||||||
XTimeline,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
column: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
isStacked: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
mediaOnly() {
|
mediaOnly() {
|
||||||
(this.$refs.timeline as any).reload();
|
(this.$refs.timeline as any).reload();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
if (this.column.listId == null) {
|
|
||||||
this.setList();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async setList() {
|
|
||||||
const lists = await os.api('users/lists/list');
|
|
||||||
const { canceled, result: list } = await os.select({
|
|
||||||
title: this.$ts.selectList,
|
|
||||||
items: lists.map(x => ({
|
|
||||||
value: x, text: x.name
|
|
||||||
})),
|
|
||||||
default: this.column.listId
|
|
||||||
});
|
|
||||||
if (canceled) return;
|
|
||||||
updateColumn(this.column.id, {
|
|
||||||
listId: list.id
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
(this.$refs.timeline as any).focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked">
|
<XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header>
|
<template #header>
|
||||||
<template v-if="pageInfo">
|
<template v-if="pageInfo">
|
||||||
<i :class="pageInfo.icon"></i>
|
<i :class="pageInfo.icon"></i>
|
||||||
|
@ -20,72 +20,59 @@
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import { deckStore, Column } from '@/ui/deck/deck-store';
|
||||||
import { deckStore } from '@/ui/deck/deck-store';
|
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
import { router } from '@/router';
|
||||||
|
|
||||||
export default defineComponent({
|
defineProps<{
|
||||||
components: {
|
column: Column;
|
||||||
XColumn,
|
isStacked: boolean;
|
||||||
XNotes
|
}>();
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const emit = defineEmits<{
|
||||||
column: {
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
type: Object,
|
}>();
|
||||||
required: true
|
|
||||||
},
|
|
||||||
isStacked: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
let pageInfo = $ref<Record<string, any> | null>(null);
|
||||||
return {
|
|
||||||
deckStore,
|
|
||||||
pageInfo: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
function changePage(page) {
|
||||||
changePage(page) {
|
|
||||||
if (page == null) return;
|
if (page == null) return;
|
||||||
if (page[symbols.PAGE_INFO]) {
|
if (page[symbols.PAGE_INFO]) {
|
||||||
this.pageInfo = page[symbols.PAGE_INFO];
|
pageInfo = page[symbols.PAGE_INFO];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
/*
|
||||||
back() {
|
function back() {
|
||||||
history.back();
|
history.back();
|
||||||
},
|
}
|
||||||
|
*/
|
||||||
|
function onContextmenu(ev: MouseEvent) {
|
||||||
|
if (!ev.target) return;
|
||||||
|
|
||||||
onContextmenu(ev: MouseEvent) {
|
|
||||||
const isLink = (el: HTMLElement) => {
|
const isLink = (el: HTMLElement) => {
|
||||||
if (el.tagName === 'A') return true;
|
if (el.tagName === 'A') return true;
|
||||||
if (el.parentElement) {
|
if (el.parentElement) {
|
||||||
return isLink(el.parentElement);
|
return isLink(el.parentElement);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (isLink(ev.target)) return;
|
if (isLink(ev.target as HTMLElement)) return;
|
||||||
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return;
|
if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes((ev.target as HTMLElement).tagName) || (ev.target as HTMLElement).attributes['contenteditable']) return;
|
||||||
if (window.getSelection().toString() !== '') return;
|
if (window.getSelection()?.toString() !== '') return;
|
||||||
const path = this.$route.path;
|
const path = router.currentRoute.value.path;
|
||||||
os.contextMenu([{
|
os.contextMenu([{
|
||||||
type: 'label',
|
type: 'label',
|
||||||
text: path,
|
text: path,
|
||||||
}, {
|
}, {
|
||||||
icon: 'fas fa-window-maximize',
|
icon: 'fas fa-window-maximize',
|
||||||
text: this.$ts.openInWindow,
|
text: i18n.ts.openInWindow,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.pageWindow(path);
|
os.pageWindow(path);
|
||||||
}
|
}
|
||||||
}], ev);
|
}], ev);
|
||||||
},
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :column="column" :is-stacked="isStacked">
|
<XColumn :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header><i class="fas fa-at" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
<template #header><i class="fas fa-at" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
||||||
|
|
||||||
<XNotes :pagination="pagination"/>
|
<XNotes :pagination="pagination"/>
|
||||||
|
@ -10,13 +10,17 @@
|
||||||
import { } from 'vue';
|
import { } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as os from '@/os';
|
import { Column } from './deck-store';
|
||||||
|
|
||||||
const props = defineProps<{
|
defineProps<{
|
||||||
column: Record<string, unknown>; // TODO
|
column: Column;
|
||||||
isStacked: boolean;
|
isStacked: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const pagination = {
|
const pagination = {
|
||||||
endpoint: 'notes/mentions' as const,
|
endpoint: 'notes/mentions' as const,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
|
|
@ -1,53 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :column="column" :is-stacked="isStacked" :func="{ handler: func, title: $ts.notificationSetting }">
|
<XColumn :column="column" :is-stacked="isStacked" :func="{ handler: func, title: $ts.notificationSetting }" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header><i class="fas fa-bell" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
<template #header><i class="fas fa-bell" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
||||||
|
|
||||||
<XNotifications :include-types="column.includingTypes"/>
|
<XNotifications :include-types="column.includingTypes"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XNotifications from '@/components/notifications.vue';
|
import XNotifications from '@/components/notifications.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { updateColumn } from './deck-store';
|
import { updateColumn } from './deck-store';
|
||||||
|
import { Column } from './deck-store';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
components: {
|
column: Column;
|
||||||
XColumn,
|
isStacked: boolean;
|
||||||
XNotifications
|
}>();
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const emit = defineEmits<{
|
||||||
column: {
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
type: Object,
|
}>();
|
||||||
required: true
|
|
||||||
},
|
|
||||||
isStacked: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
function func() {
|
||||||
return {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
func() {
|
|
||||||
os.popup(import('@/components/notification-setting-window.vue'), {
|
os.popup(import('@/components/notification-setting-window.vue'), {
|
||||||
includingTypes: this.column.includingTypes,
|
includingTypes: props.column.includingTypes,
|
||||||
}, {
|
}, {
|
||||||
done: async (res) => {
|
done: async (res) => {
|
||||||
const { includingTypes } = res;
|
const { includingTypes } = res;
|
||||||
updateColumn(this.column.id, {
|
updateColumn(props.column.id, {
|
||||||
includingTypes: includingTypes
|
includingTypes: includingTypes
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :func="{ handler: setType, title: $ts.timeline }" :column="column" :is-stacked="isStacked" :indicated="indicated" @change-active-state="onChangeActiveState">
|
<XColumn :func="{ handler: setType, title: $ts.timeline }" :column="column" :is-stacked="isStacked" :indicated="indicated" @change-active-state="onChangeActiveState" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header>
|
<template #header>
|
||||||
<i v-if="column.tl === 'home'" class="fas fa-home"></i>
|
<i v-if="column.tl === 'home'" class="fas fa-home"></i>
|
||||||
<i v-else-if="column.tl === 'local'" class="fas fa-comments"></i>
|
<i v-else-if="column.tl === 'local'" class="fas fa-comments"></i>
|
||||||
|
@ -15,108 +15,103 @@
|
||||||
</p>
|
</p>
|
||||||
<p class="desc">{{ $t('disabled-timeline.description') }}</p>
|
<p class="desc">{{ $t('disabled-timeline.description') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<XTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl" @after="() => $emit('loaded')" @queue="queueUpdated" @note="onNote"/>
|
<XTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl" @after="() => emit('loaded')" @queue="queueUpdated" @note="onNote"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XTimeline from '@/components/timeline.vue';
|
import XTimeline from '@/components/timeline.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { removeColumn, updateColumn } from './deck-store';
|
import { removeColumn, updateColumn, Column } from './deck-store';
|
||||||
|
import { $i } from '@/account';
|
||||||
|
import { instance } from '@/instance';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
components: {
|
column: Column;
|
||||||
XColumn,
|
isStacked: boolean;
|
||||||
XTimeline,
|
}>();
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const emit = defineEmits<{
|
||||||
column: {
|
(e: 'loaded'): void;
|
||||||
type: Object,
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
required: true
|
}>();
|
||||||
},
|
|
||||||
isStacked: {
|
let disabled = $ref(false);
|
||||||
type: Boolean,
|
let indicated = $ref(false);
|
||||||
required: true
|
let columnActive = $ref(true);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.column.tl == null) {
|
||||||
|
setType();
|
||||||
|
} else if ($i) {
|
||||||
|
disabled = !$i.isModerator && !$i.isAdmin && (
|
||||||
|
instance.disableLocalTimeline && ['local', 'social'].includes(props.column.tl) ||
|
||||||
|
instance.disableGlobalTimeline && ['global'].includes(props.column.tl));
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
|
|
||||||
data() {
|
async function setType() {
|
||||||
return {
|
const { canceled, result: src } = await os.select({
|
||||||
disabled: false,
|
title: i18n.ts.timeline,
|
||||||
indicated: false,
|
items: [{
|
||||||
columnActive: true,
|
value: 'home' as const, text: i18n.ts._timelines.home
|
||||||
};
|
}, {
|
||||||
},
|
value: 'local' as const, text: i18n.ts._timelines.local
|
||||||
|
}, {
|
||||||
|
value: 'social' as const, text: i18n.ts._timelines.social
|
||||||
|
}, {
|
||||||
|
value: 'global' as const, text: i18n.ts._timelines.global
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
if (canceled) {
|
||||||
|
if (props.column.tl == null) {
|
||||||
|
removeColumn(props.column.id);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateColumn(props.column.id, {
|
||||||
|
tl: src
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function queueUpdated(q) {
|
||||||
|
if (columnActive) {
|
||||||
|
indicated = q !== 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNote() {
|
||||||
|
if (!columnActive) {
|
||||||
|
indicated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChangeActiveState(state) {
|
||||||
|
columnActive = state;
|
||||||
|
|
||||||
|
if (columnActive) {
|
||||||
|
indicated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
export default defineComponent({
|
||||||
watch: {
|
watch: {
|
||||||
mediaOnly() {
|
mediaOnly() {
|
||||||
(this.$refs.timeline as any).reload();
|
(this.$refs.timeline as any).reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
|
||||||
if (this.column.tl == null) {
|
|
||||||
this.setType();
|
|
||||||
} else {
|
|
||||||
this.disabled = !this.$i.isModerator && !this.$i.isAdmin && (
|
|
||||||
this.$instance.disableLocalTimeline && ['local', 'social'].includes(this.column.tl) ||
|
|
||||||
this.$instance.disableGlobalTimeline && ['global'].includes(this.column.tl));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async setType() {
|
|
||||||
const { canceled, result: src } = await os.select({
|
|
||||||
title: this.$ts.timeline,
|
|
||||||
items: [{
|
|
||||||
value: 'home', text: this.$ts._timelines.home
|
|
||||||
}, {
|
|
||||||
value: 'local', text: this.$ts._timelines.local
|
|
||||||
}, {
|
|
||||||
value: 'social', text: this.$ts._timelines.social
|
|
||||||
}, {
|
|
||||||
value: 'global', text: this.$ts._timelines.global
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
if (canceled) {
|
|
||||||
if (this.column.tl == null) {
|
|
||||||
removeColumn(this.column.id);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateColumn(this.column.id, {
|
|
||||||
tl: src
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
queueUpdated(q) {
|
|
||||||
if (this.columnActive) {
|
|
||||||
this.indicated = q !== 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onNote() {
|
|
||||||
if (!this.columnActive) {
|
|
||||||
this.indicated = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeActiveState(state) {
|
|
||||||
this.columnActive = state;
|
|
||||||
|
|
||||||
if (this.columnActive) {
|
|
||||||
this.indicated = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
(this.$refs.timeline as any).focus();
|
(this.$refs.timeline as any).focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,64 +1,49 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :func="{ handler: func, title: $ts.editWidgets }" :naked="true" :column="column" :is-stacked="isStacked">
|
<XColumn :func="{ handler: func, title: $ts.editWidgets }" :naked="true" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header><i class="fas fa-window-maximize" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
<template #header><i class="fas fa-window-maximize" style="margin-right: 8px;"></i>{{ column.name }}</template>
|
||||||
|
|
||||||
<div class="wtdtxvec">
|
<div class="wtdtxvec">
|
||||||
<XWidgets :edit="edit" :widgets="column.widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="edit = false"/>
|
<XWidgets v-if="column.widgets" :edit="edit" :widgets="column.widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="edit = false"/>
|
||||||
</div>
|
</div>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, defineAsyncComponent } from 'vue';
|
import { } from 'vue';
|
||||||
import XWidgets from '@/components/widgets.vue';
|
import XWidgets from '@/components/widgets.vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import { addColumnWidget, removeColumnWidget, setColumnWidgets, updateColumnWidget } from './deck-store';
|
import { addColumnWidget, Column, removeColumnWidget, setColumnWidgets, updateColumnWidget } from './deck-store';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
components: {
|
column: Column;
|
||||||
XColumn,
|
isStacked: boolean;
|
||||||
XWidgets,
|
}>();
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const emit = defineEmits<{
|
||||||
column: {
|
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||||
type: Object,
|
}>();
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
isStacked: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
let edit = $ref(false);
|
||||||
return {
|
|
||||||
edit: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
function addWidget(widget) {
|
||||||
addWidget(widget) {
|
addColumnWidget(props.column.id, widget);
|
||||||
addColumnWidget(this.column.id, widget);
|
}
|
||||||
},
|
|
||||||
|
|
||||||
removeWidget(widget) {
|
function removeWidget(widget) {
|
||||||
removeColumnWidget(this.column.id, widget);
|
removeColumnWidget(props.column.id, widget);
|
||||||
},
|
}
|
||||||
|
|
||||||
updateWidget({ id, data }) {
|
function updateWidget({ id, data }) {
|
||||||
updateColumnWidget(this.column.id, id, data);
|
updateColumnWidget(props.column.id, id, data);
|
||||||
},
|
}
|
||||||
|
|
||||||
updateWidgets(widgets) {
|
function updateWidgets(widgets) {
|
||||||
setColumnWidgets(this.column.id, widgets);
|
setColumnWidgets(props.column.id, widgets);
|
||||||
},
|
}
|
||||||
|
|
||||||
func() {
|
function func() {
|
||||||
this.edit = !this.edit;
|
edit = !edit;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -1,58 +1,50 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="efzpzdvf">
|
<div class="efzpzdvf">
|
||||||
<XWidgets :edit="editMode" :widgets="$store.reactiveState.widgets.value" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
|
<XWidgets :edit="editMode" :widgets="defaultStore.reactiveState.widgets.value" @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="fas fa-check"></i> {{ $ts.editWidgetsExit }}</button>
|
<button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="fas fa-check"></i> {{ i18n.ts.editWidgetsExit }}</button>
|
||||||
<button v-else class="_textButton" style="font-size: 0.9em;" @click="editMode = true"><i class="fas fa-pencil-alt"></i> {{ $ts.editWidgets }}</button>
|
<button v-else class="_textButton" style="font-size: 0.9em;" @click="editMode = true"><i class="fas fa-pencil-alt"></i> {{ i18n.ts.editWidgets }}</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, defineAsyncComponent } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import XWidgets from '@/components/widgets.vue';
|
import XWidgets from '@/components/widgets.vue';
|
||||||
import * as os from '@/os';
|
import { i18n } from '@/i18n';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
|
|
||||||
export default defineComponent({
|
const emit = defineEmits<{
|
||||||
components: {
|
(e: 'mounted', el: Element): void;
|
||||||
XWidgets
|
}>();
|
||||||
},
|
|
||||||
|
|
||||||
emits: ['mounted'],
|
let editMode = $ref(false);
|
||||||
|
let rootEl = $ref<HTMLDivElement>();
|
||||||
|
|
||||||
data() {
|
onMounted(() => {
|
||||||
return {
|
emit('mounted', rootEl);
|
||||||
editMode: false,
|
});
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
function addWidget(widget) {
|
||||||
this.$emit('mounted', this.$el);
|
defaultStore.set('widgets', [{
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
addWidget(widget) {
|
|
||||||
this.$store.set('widgets', [{
|
|
||||||
...widget,
|
...widget,
|
||||||
place: null,
|
place: null,
|
||||||
}, ...this.$store.state.widgets]);
|
}, ...defaultStore.state.widgets]);
|
||||||
},
|
}
|
||||||
|
|
||||||
removeWidget(widget) {
|
function removeWidget(widget) {
|
||||||
this.$store.set('widgets', this.$store.state.widgets.filter(w => w.id != widget.id));
|
defaultStore.set('widgets', defaultStore.state.widgets.filter(w => w.id != widget.id));
|
||||||
},
|
}
|
||||||
|
|
||||||
updateWidget({ id, data }) {
|
function updateWidget({ id, data }) {
|
||||||
this.$store.set('widgets', this.$store.state.widgets.map(w => w.id === id ? {
|
defaultStore.set('widgets', defaultStore.state.widgets.map(w => w.id === id ? {
|
||||||
...w,
|
...w,
|
||||||
data: data
|
data: data
|
||||||
} : w));
|
} : w));
|
||||||
},
|
}
|
||||||
|
|
||||||
updateWidgets(widgets) {
|
function updateWidgets(widgets) {
|
||||||
this.$store.set('widgets', widgets);
|
defaultStore.set('widgets', widgets);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
Loading…
Reference in New Issue