forked from FoundKeyGang/FoundKey
wip
This commit is contained in:
parent
0d8c83f27c
commit
69b5de3346
11 changed files with 505 additions and 163 deletions
|
@ -1,6 +1,7 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
import analogClock from './analog-clock.vue';
|
import analogClock from './analog-clock.vue';
|
||||||
|
import menu from './menu.vue';
|
||||||
import signin from './signin.vue';
|
import signin from './signin.vue';
|
||||||
import signup from './signup.vue';
|
import signup from './signup.vue';
|
||||||
import forkit from './forkit.vue';
|
import forkit from './forkit.vue';
|
||||||
|
@ -29,6 +30,7 @@ import Othello from './othello.vue';
|
||||||
import welcomeTimeline from './welcome-timeline.vue';
|
import welcomeTimeline from './welcome-timeline.vue';
|
||||||
|
|
||||||
Vue.component('mk-analog-clock', analogClock);
|
Vue.component('mk-analog-clock', analogClock);
|
||||||
|
Vue.component('mk-menu', menu);
|
||||||
Vue.component('mk-signin', signin);
|
Vue.component('mk-signin', signin);
|
||||||
Vue.component('mk-signup', signup);
|
Vue.component('mk-signup', signup);
|
||||||
Vue.component('mk-forkit', forkit);
|
Vue.component('mk-forkit', forkit);
|
||||||
|
|
153
src/client/app/common/views/components/menu.vue
Normal file
153
src/client/app/common/views/components/menu.vue
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
<template>
|
||||||
|
<div class="mk-menu">
|
||||||
|
<div class="backdrop" ref="backdrop" @click="close"></div>
|
||||||
|
<div class="popover" :class="{ compact }" ref="popover">
|
||||||
|
<button v-for="item in items" @click="clicked(item.onClick)" v-html="item.content"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import * as anime from 'animejs';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
props: ['source', 'compact', 'items'],
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const popover = this.$refs.popover as any;
|
||||||
|
|
||||||
|
const rect = this.source.getBoundingClientRect();
|
||||||
|
const width = popover.offsetWidth;
|
||||||
|
const height = popover.offsetHeight;
|
||||||
|
|
||||||
|
if (this.compact) {
|
||||||
|
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
||||||
|
const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2);
|
||||||
|
popover.style.left = (x - (width / 2)) + 'px';
|
||||||
|
popover.style.top = (y - (height / 2)) + 'px';
|
||||||
|
} else {
|
||||||
|
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
||||||
|
const y = rect.top + window.pageYOffset + this.source.offsetHeight;
|
||||||
|
popover.style.left = (x - (width / 2)) + 'px';
|
||||||
|
popover.style.top = y + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.backdrop,
|
||||||
|
opacity: 1,
|
||||||
|
duration: 100,
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.popover,
|
||||||
|
opacity: 1,
|
||||||
|
scale: [0.5, 1],
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clicked(fn) {
|
||||||
|
fn();
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
(this.$refs.backdrop as any).style.pointerEvents = 'none';
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.backdrop,
|
||||||
|
opacity: 0,
|
||||||
|
duration: 200,
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
|
||||||
|
(this.$refs.popover as any).style.pointerEvents = 'none';
|
||||||
|
anime({
|
||||||
|
targets: this.$refs.popover,
|
||||||
|
opacity: 0,
|
||||||
|
scale: 0.5,
|
||||||
|
duration: 200,
|
||||||
|
easing: 'easeInBack',
|
||||||
|
complete: () => {
|
||||||
|
this.$emit('closed');
|
||||||
|
this.$destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
@import '~const.styl'
|
||||||
|
|
||||||
|
$border-color = rgba(27, 31, 35, 0.15)
|
||||||
|
|
||||||
|
.mk-menu
|
||||||
|
position initial
|
||||||
|
|
||||||
|
> .backdrop
|
||||||
|
position fixed
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
z-index 10000
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background rgba(#000, 0.1)
|
||||||
|
opacity 0
|
||||||
|
|
||||||
|
> .popover
|
||||||
|
position absolute
|
||||||
|
z-index 10001
|
||||||
|
padding 8px 0
|
||||||
|
background #fff
|
||||||
|
border 1px solid $border-color
|
||||||
|
border-radius 4px
|
||||||
|
box-shadow 0 3px 12px rgba(27, 31, 35, 0.15)
|
||||||
|
transform scale(0.5)
|
||||||
|
opacity 0
|
||||||
|
|
||||||
|
$balloon-size = 16px
|
||||||
|
|
||||||
|
&:not(.compact)
|
||||||
|
margin-top $balloon-size
|
||||||
|
transform-origin center -($balloon-size)
|
||||||
|
|
||||||
|
&:before
|
||||||
|
content ""
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
top -($balloon-size * 2)
|
||||||
|
left s('calc(50% - %s)', $balloon-size)
|
||||||
|
border-top solid $balloon-size transparent
|
||||||
|
border-left solid $balloon-size transparent
|
||||||
|
border-right solid $balloon-size transparent
|
||||||
|
border-bottom solid $balloon-size $border-color
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
top -($balloon-size * 2) + 1.5px
|
||||||
|
left s('calc(50% - %s)', $balloon-size)
|
||||||
|
border-top solid $balloon-size transparent
|
||||||
|
border-left solid $balloon-size transparent
|
||||||
|
border-right solid $balloon-size transparent
|
||||||
|
border-bottom solid $balloon-size #fff
|
||||||
|
|
||||||
|
> button
|
||||||
|
display block
|
||||||
|
padding 8px 16px
|
||||||
|
width 100%
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
color $theme-color-foreground
|
||||||
|
background $theme-color
|
||||||
|
text-decoration none
|
||||||
|
|
||||||
|
&:active
|
||||||
|
color $theme-color-foreground
|
||||||
|
background darken($theme-color, 10%)
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,55 +1,41 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-note-menu">
|
<div class="mk-note-menu" style="position:initial">
|
||||||
<div class="backdrop" ref="backdrop" @click="close"></div>
|
<mk-menu ref="menu" :source="source" :compact="compact" :items="items" @closed="$destroy"/>
|
||||||
<div class="popover" :class="{ compact }" ref="popover">
|
|
||||||
<button @click="favorite">%i18n:@favorite%</button>
|
|
||||||
<button v-if="note.userId == $store.state.i.id" @click="pin">%i18n:@pin%</button>
|
|
||||||
<button v-if="note.userId == $store.state.i.id" @click="del">%i18n:@delete%</button>
|
|
||||||
<a v-if="note.uri" :href="note.uri" target="_blank">%i18n:@remote%</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import * as anime from 'animejs';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['note', 'source', 'compact'],
|
props: ['note', 'source', 'compact'],
|
||||||
mounted() {
|
computed: {
|
||||||
this.$nextTick(() => {
|
items() {
|
||||||
const popover = this.$refs.popover as any;
|
const items = [];
|
||||||
|
items.push({
|
||||||
const rect = this.source.getBoundingClientRect();
|
content: '%i18n:@favorite%',
|
||||||
const width = popover.offsetWidth;
|
onClick: this.favorite
|
||||||
const height = popover.offsetHeight;
|
});
|
||||||
|
if (this.note.userId == this.$store.state.i.id) {
|
||||||
if (this.compact) {
|
items.push({
|
||||||
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
content: '%i18n:@pin%',
|
||||||
const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2);
|
onClick: this.pin
|
||||||
popover.style.left = (x - (width / 2)) + 'px';
|
});
|
||||||
popover.style.top = (y - (height / 2)) + 'px';
|
items.push({
|
||||||
} else {
|
content: '%i18n:@delete%',
|
||||||
const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
|
onClick: this.del
|
||||||
const y = rect.top + window.pageYOffset + this.source.offsetHeight;
|
});
|
||||||
popover.style.left = (x - (width / 2)) + 'px';
|
|
||||||
popover.style.top = y + 'px';
|
|
||||||
}
|
}
|
||||||
|
if (this.note.uri) {
|
||||||
anime({
|
items.push({
|
||||||
targets: this.$refs.backdrop,
|
content: '%i18n:@remote%',
|
||||||
opacity: 1,
|
onClick: () => {
|
||||||
duration: 100,
|
window.open(this.note.uri, '_blank');
|
||||||
easing: 'linear'
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
anime({
|
return items;
|
||||||
targets: this.$refs.popover,
|
}
|
||||||
opacity: 1,
|
|
||||||
scale: [0.5, 1],
|
|
||||||
duration: 500
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
pin() {
|
pin() {
|
||||||
|
@ -78,98 +64,8 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
(this.$refs.backdrop as any).style.pointerEvents = 'none';
|
this.$refs.menu.close();
|
||||||
anime({
|
|
||||||
targets: this.$refs.backdrop,
|
|
||||||
opacity: 0,
|
|
||||||
duration: 200,
|
|
||||||
easing: 'linear'
|
|
||||||
});
|
|
||||||
|
|
||||||
(this.$refs.popover as any).style.pointerEvents = 'none';
|
|
||||||
anime({
|
|
||||||
targets: this.$refs.popover,
|
|
||||||
opacity: 0,
|
|
||||||
scale: 0.5,
|
|
||||||
duration: 200,
|
|
||||||
easing: 'easeInBack',
|
|
||||||
complete: () => this.$destroy()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
@import '~const.styl'
|
|
||||||
|
|
||||||
$border-color = rgba(27, 31, 35, 0.15)
|
|
||||||
|
|
||||||
.mk-note-menu
|
|
||||||
position initial
|
|
||||||
|
|
||||||
> .backdrop
|
|
||||||
position fixed
|
|
||||||
top 0
|
|
||||||
left 0
|
|
||||||
z-index 10000
|
|
||||||
width 100%
|
|
||||||
height 100%
|
|
||||||
background rgba(#000, 0.1)
|
|
||||||
opacity 0
|
|
||||||
|
|
||||||
> .popover
|
|
||||||
position absolute
|
|
||||||
z-index 10001
|
|
||||||
padding 8px 0
|
|
||||||
background #fff
|
|
||||||
border 1px solid $border-color
|
|
||||||
border-radius 4px
|
|
||||||
box-shadow 0 3px 12px rgba(27, 31, 35, 0.15)
|
|
||||||
transform scale(0.5)
|
|
||||||
opacity 0
|
|
||||||
|
|
||||||
$balloon-size = 16px
|
|
||||||
|
|
||||||
&:not(.compact)
|
|
||||||
margin-top $balloon-size
|
|
||||||
transform-origin center -($balloon-size)
|
|
||||||
|
|
||||||
&:before
|
|
||||||
content ""
|
|
||||||
display block
|
|
||||||
position absolute
|
|
||||||
top -($balloon-size * 2)
|
|
||||||
left s('calc(50% - %s)', $balloon-size)
|
|
||||||
border-top solid $balloon-size transparent
|
|
||||||
border-left solid $balloon-size transparent
|
|
||||||
border-right solid $balloon-size transparent
|
|
||||||
border-bottom solid $balloon-size $border-color
|
|
||||||
|
|
||||||
&:after
|
|
||||||
content ""
|
|
||||||
display block
|
|
||||||
position absolute
|
|
||||||
top -($balloon-size * 2) + 1.5px
|
|
||||||
left s('calc(50% - %s)', $balloon-size)
|
|
||||||
border-top solid $balloon-size transparent
|
|
||||||
border-left solid $balloon-size transparent
|
|
||||||
border-right solid $balloon-size transparent
|
|
||||||
border-bottom solid $balloon-size #fff
|
|
||||||
|
|
||||||
> button
|
|
||||||
> a
|
|
||||||
display block
|
|
||||||
padding 8px 16px
|
|
||||||
width 100%
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
color $theme-color-foreground
|
|
||||||
background $theme-color
|
|
||||||
text-decoration none
|
|
||||||
|
|
||||||
&:active
|
|
||||||
color $theme-color-foreground
|
|
||||||
background darken($theme-color, 10%)
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs">
|
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs">
|
||||||
<header :class="{ indicate }">
|
<header :class="{ indicate }">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
|
<button ref="menu" @click="menu">%fa:caret-down%</button>
|
||||||
</header>
|
</header>
|
||||||
<div ref="body">
|
<div ref="body">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -11,8 +12,16 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import Menu from '../../../../common/views/components/menu.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
indicate: false
|
indicate: false
|
||||||
|
@ -48,6 +57,29 @@ export default Vue.extend({
|
||||||
const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight;
|
const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight;
|
||||||
if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom');
|
if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom');
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
menu() {
|
||||||
|
this.os.new(Menu, {
|
||||||
|
source: this.$refs.menu,
|
||||||
|
compact: false,
|
||||||
|
items: [{
|
||||||
|
content: '%fa:arrow-left% %i18n:@swap-left%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/swapLeftDeckColumn', this.id);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
content: '%fa:arrow-right% %i18n:@swap-right%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/swapRightDeckColumn', this.id);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
content: '%fa:trash-alt R% %i18n:@remove%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/removeDeckColumn', this.id);
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -57,6 +89,8 @@ export default Vue.extend({
|
||||||
@import '~const.styl'
|
@import '~const.styl'
|
||||||
|
|
||||||
root(isDark)
|
root(isDark)
|
||||||
|
$header-height = 42px
|
||||||
|
|
||||||
flex 1
|
flex 1
|
||||||
min-width 330px
|
min-width 330px
|
||||||
max-width 330px
|
max-width 330px
|
||||||
|
@ -68,7 +102,7 @@ root(isDark)
|
||||||
|
|
||||||
> header
|
> header
|
||||||
z-index 1
|
z-index 1
|
||||||
line-height 42px
|
line-height $header-height
|
||||||
padding 0 16px
|
padding 0 16px
|
||||||
color isDark ? #e3e5e8 : #888
|
color isDark ? #e3e5e8 : #888
|
||||||
background isDark ? #313543 : #fff
|
background isDark ? #313543 : #fff
|
||||||
|
@ -77,8 +111,26 @@ root(isDark)
|
||||||
&.indicate
|
&.indicate
|
||||||
box-shadow 0 3px 0 0 $theme-color
|
box-shadow 0 3px 0 0 $theme-color
|
||||||
|
|
||||||
|
> span
|
||||||
|
[data-fa]
|
||||||
|
margin-right 8px
|
||||||
|
|
||||||
|
> button
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
width $header-height
|
||||||
|
line-height $header-height
|
||||||
|
color isDark ? #9baec8 : #ccc
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
color isDark ? #b2c1d5 : #aaa
|
||||||
|
|
||||||
|
&:active
|
||||||
|
color isDark ? #b2c1d5 : #999
|
||||||
|
|
||||||
> div
|
> div
|
||||||
height calc(100% - 42px)
|
height calc(100% - $header-height)
|
||||||
overflow auto
|
overflow auto
|
||||||
overflow-x hidden
|
overflow-x hidden
|
||||||
|
|
||||||
|
|
103
src/client/app/desktop/views/pages/deck/deck.list-tl.vue
Normal file
103
src/client/app/desktop/views/pages/deck/deck.list-tl.vue
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<x-notes ref="timeline" :more="existMore ? more : null"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import XNotes from './deck.notes.vue';
|
||||||
|
import { UserListStream } from '../../../../common/scripts/streaming/user-list';
|
||||||
|
|
||||||
|
const fetchLimit = 10;
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XNotes
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
list: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetching: true,
|
||||||
|
moreFetching: false,
|
||||||
|
existMore: false,
|
||||||
|
connection: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
if (this.connection) this.connection.close();
|
||||||
|
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
|
||||||
|
this.connection.on('note', this.onNote);
|
||||||
|
this.connection.on('userAdded', this.onUserAdded);
|
||||||
|
this.connection.on('userRemoved', this.onUserRemoved);
|
||||||
|
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.connection.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
this.fetching = true;
|
||||||
|
|
||||||
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
|
(this as any).api('notes/user-list-timeline', {
|
||||||
|
listId: this.list.id,
|
||||||
|
limit: fetchLimit + 1,
|
||||||
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
|
}).then(notes => {
|
||||||
|
if (notes.length == fetchLimit + 1) {
|
||||||
|
notes.pop();
|
||||||
|
this.existMore = true;
|
||||||
|
}
|
||||||
|
res(notes);
|
||||||
|
this.fetching = false;
|
||||||
|
this.$emit('loaded');
|
||||||
|
}, rej);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
more() {
|
||||||
|
this.moreFetching = true;
|
||||||
|
|
||||||
|
const promise = (this as any).api('notes/user-list-timeline', {
|
||||||
|
listId: this.list.id,
|
||||||
|
limit: fetchLimit + 1,
|
||||||
|
untilId: (this.$refs.timeline as any).tail().id,
|
||||||
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.then(notes => {
|
||||||
|
if (notes.length == fetchLimit + 1) {
|
||||||
|
notes.pop();
|
||||||
|
} else {
|
||||||
|
this.existMore = false;
|
||||||
|
}
|
||||||
|
notes.forEach(n => (this.$refs.timeline as any).append(n));
|
||||||
|
this.moreFetching = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
onNote(note) {
|
||||||
|
// Prepend a note
|
||||||
|
(this.$refs.timeline as any).prepend(note);
|
||||||
|
},
|
||||||
|
onUserAdded() {
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
onUserRemoved() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<x-column>
|
<x-column :id="id">
|
||||||
<span slot="header">%fa:bell R% %i18n:@notifications%</span>
|
<span slot="header">%fa:bell R% %i18n:@notifications%</span>
|
||||||
|
|
||||||
<x-notifications/>
|
<x-notifications/>
|
||||||
|
@ -17,6 +17,13 @@ export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XColumn,
|
XColumn,
|
||||||
XNotifications
|
XNotifications
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<x-column>
|
<x-column :id="column.id">
|
||||||
<span slot="header">
|
<span slot="header">
|
||||||
<template v-if="src == 'home'">%fa:home% %i18n:@home%</template>
|
<template v-if="column.type == 'home'">%fa:home%%i18n:@home%</template>
|
||||||
<template v-if="src == 'local'">%fa:R comments% %i18n:@local%</template>
|
<template v-if="column.type == 'local'">%fa:R comments%%i18n:@local%</template>
|
||||||
<template v-if="src == 'global'">%fa:globe% %i18n:@global%</template>
|
<template v-if="column.type == 'global'">%fa:globe%%i18n:@global%</template>
|
||||||
<template v-if="src == 'list'">%fa:list% {{ list.title }}</template>
|
<template v-if="column.type == 'list'">%fa:list%{{ column.list.title }}</template>
|
||||||
</span>
|
</span>
|
||||||
<x-tl :src="src"/>
|
|
||||||
|
<x-list-tl v-if="column.type == 'list'" :list="column.list"/>
|
||||||
|
<x-tl v-else :src="column.type"/>
|
||||||
</x-column>
|
</x-column>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -16,18 +18,20 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XColumn from './deck.column.vue';
|
import XColumn from './deck.column.vue';
|
||||||
import XTl from './deck.tl.vue';
|
import XTl from './deck.tl.vue';
|
||||||
|
import XListTl from './deck.list-tl.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XColumn,
|
XColumn,
|
||||||
XTl
|
XTl,
|
||||||
|
XListTl
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
src: {
|
column: {
|
||||||
type: String,
|
type: Object,
|
||||||
required: false
|
required: true
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -27,9 +27,7 @@ export default Vue.extend({
|
||||||
moreFetching: false,
|
moreFetching: false,
|
||||||
existMore: false,
|
existMore: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
connectionId: null
|
||||||
unreadCount: 0,
|
|
||||||
date: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -74,17 +72,12 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
mount(root) {
|
|
||||||
this.$refs.timeline.mount(root);
|
|
||||||
},
|
|
||||||
|
|
||||||
fetch() {
|
fetch() {
|
||||||
this.fetching = true;
|
this.fetching = true;
|
||||||
|
|
||||||
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
(this as any).api(this.endpoint, {
|
(this as any).api(this.endpoint, {
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilDate: this.date ? this.date.getTime() : undefined,
|
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
<mk-ui :class="$style.root">
|
<mk-ui :class="$style.root">
|
||||||
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
|
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
|
||||||
<template v-for="column in columns">
|
<template v-for="column in columns">
|
||||||
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id"/>
|
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :id="column.id"/>
|
||||||
<x-tl-column v-if="column.type == 'home'" :key="column.id" src="home"/>
|
<x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/>
|
||||||
<x-tl-column v-if="column.type == 'local'" :key="column.id" src="local"/>
|
<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/>
|
||||||
<x-tl-column v-if="column.type == 'global'" :key="column.id" src="global"/>
|
<x-tl-column v-if="column.type == 'global'" :key="column.id" :column="column"/>
|
||||||
|
<x-tl-column v-if="column.type == 'list'" :key="column.id" :column="column"/>
|
||||||
</template>
|
</template>
|
||||||
<button>%fa:plus%</button>
|
<button ref="add" @click="add">%fa:plus%</button>
|
||||||
</div>
|
</div>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
</template>
|
</template>
|
||||||
|
@ -16,6 +17,8 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XTlColumn from './deck.tl-column.vue';
|
import XTlColumn from './deck.tl-column.vue';
|
||||||
import XNotificationsColumn from './deck.notifications-column.vue';
|
import XNotificationsColumn from './deck.notifications-column.vue';
|
||||||
|
import Menu from '../../../../common/views/components/menu.vue';
|
||||||
|
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
@ -55,6 +58,61 @@ export default Vue.extend({
|
||||||
value: deck
|
value: deck
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
add() {
|
||||||
|
this.os.new(Menu, {
|
||||||
|
source: this.$refs.add,
|
||||||
|
compact: true,
|
||||||
|
items: [{
|
||||||
|
content: '%i18n:@home%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'home'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
content: '%i18n:@local%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'local'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
content: '%i18n:@global%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'global'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
content: '%i18n:@list%',
|
||||||
|
onClick: () => {
|
||||||
|
const w = (this as any).os.new(MkUserListsWindow);
|
||||||
|
w.$once('choosen', list => {
|
||||||
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'list',
|
||||||
|
list: list
|
||||||
|
});
|
||||||
|
w.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
content: '%i18n:@notifications%',
|
||||||
|
onClick: () => {
|
||||||
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'notifications'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -73,12 +73,12 @@ export default class MiOS extends EventEmitter {
|
||||||
public app: Vue;
|
public app: Vue;
|
||||||
|
|
||||||
public new(vm, props) {
|
public new(vm, props) {
|
||||||
const w = new vm({
|
const x = new vm({
|
||||||
parent: this.app,
|
parent: this.app,
|
||||||
propsData: props
|
propsData: props
|
||||||
}).$mount();
|
}).$mount();
|
||||||
document.body.appendChild(w.$el);
|
document.body.appendChild(x.$el);
|
||||||
return w;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -152,6 +152,44 @@ export default (os: MiOS) => new Vuex.Store({
|
||||||
|
|
||||||
removeMobileHomeWidget(state, widget) {
|
removeMobileHomeWidget(state, widget) {
|
||||||
state.mobileHome = state.mobileHome.filter(w => w.id != widget.id);
|
state.mobileHome = state.mobileHome.filter(w => w.id != widget.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
addDeckColumn(state, column) {
|
||||||
|
if (state.deck.columns == null) state.deck.columns = [];
|
||||||
|
state.deck.columns.push(column);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeDeckColumn(state, id) {
|
||||||
|
if (state.deck.columns == null) return;
|
||||||
|
state.deck.columns = state.deck.columns.filter(c => c.id != id);
|
||||||
|
},
|
||||||
|
|
||||||
|
swapLeftDeckColumn(state, id) {
|
||||||
|
if (state.deck.columns == null) return;
|
||||||
|
state.deck.columns.some((c, i) => {
|
||||||
|
if (c.id == id) {
|
||||||
|
const left = state.deck.columns[i - 1];
|
||||||
|
if (left) {
|
||||||
|
state.deck.columns[i - 1] = state.deck.columns[i];
|
||||||
|
state.deck.columns[i] = left;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
swapRightDeckColumn(state, id) {
|
||||||
|
if (state.deck.columns == null) return;
|
||||||
|
state.deck.columns.some((c, i) => {
|
||||||
|
if (c.id == id) {
|
||||||
|
const right = state.deck.columns[i + 1];
|
||||||
|
if (right) {
|
||||||
|
state.deck.columns[i + 1] = state.deck.columns[i];
|
||||||
|
state.deck.columns[i] = right;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -174,6 +212,42 @@ export default (os: MiOS) => new Vuex.Store({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addDeckColumn(ctx, column) {
|
||||||
|
ctx.commit('addDeckColumn', column);
|
||||||
|
|
||||||
|
os.api('i/update_client_setting', {
|
||||||
|
name: 'deck',
|
||||||
|
value: ctx.state.deck
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('removeDeckColumn', id);
|
||||||
|
|
||||||
|
os.api('i/update_client_setting', {
|
||||||
|
name: 'deck',
|
||||||
|
value: ctx.state.deck
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
swapLeftDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('swapLeftDeckColumn', id);
|
||||||
|
|
||||||
|
os.api('i/update_client_setting', {
|
||||||
|
name: 'deck',
|
||||||
|
value: ctx.state.deck
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
swapRightDeckColumn(ctx, id) {
|
||||||
|
ctx.commit('swapRightDeckColumn', id);
|
||||||
|
|
||||||
|
os.api('i/update_client_setting', {
|
||||||
|
name: 'deck',
|
||||||
|
value: ctx.state.deck
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
addHomeWidget(ctx, widget) {
|
addHomeWidget(ctx, widget) {
|
||||||
ctx.commit('addHomeWidget', widget);
|
ctx.commit('addHomeWidget', widget);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue