wip
This commit is contained in:
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<mk-window ref="window" @closed="$destroy" width="800px" height="500px" :popout="popout">
|
||||
<span slot="header" :class="$style.header">
|
||||
<p class="info" v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:desktop.tags.mk-drive-browser-window.used%</p>
|
||||
%fa:cloud%%i18n:desktop.tags.mk-drive-browser-window.drive%
|
||||
</span>
|
||||
<template slot="header">
|
||||
<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:desktop.tags.mk-drive-browser-window.used%</p>
|
||||
<span: class="$style.title">%fa:cloud%%i18n:desktop.tags.mk-drive-browser-window.drive%</span>
|
||||
</template>
|
||||
<mk-drive-browser multiple :folder="folder" ref="browser"/>
|
||||
</mk-window>
|
||||
</template>
|
||||
@ -38,7 +38,7 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="stylus" module>
|
||||
.header
|
||||
.title
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<button class="mk-follow-button"
|
||||
:class="{ wait, follow: !user.is_following, unfollow: user.is_following }"
|
||||
v-if="!init"
|
||||
@click="onClick"
|
||||
:disabled="wait"
|
||||
:title="user.is_following ? 'フォロー解除' : 'フォローする'"
|
||||
|
@ -41,10 +41,10 @@
|
||||
<div ref="left" data-place="left">
|
||||
<template v-for="widget in leftWidgets">
|
||||
<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)">
|
||||
<component :is="'mk-hw-' + widget.name" :widget="widget" :ref="widget.id"/>
|
||||
<component :is="'mkw-' + widget.name" :widget="widget" :ref="widget.id"/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<component :is="'mk-hw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/>
|
||||
<component :is="'mkw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
@ -53,10 +53,10 @@
|
||||
<div class="maintop" ref="maintop" data-place="main" v-if="customize">
|
||||
<template v-for="widget in centerWidgets">
|
||||
<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)">
|
||||
<component :is="'mk-hw-' + widget.name" :widget="widget" :ref="widget.id"/>
|
||||
<component :is="'mkw-' + widget.name" :widget="widget" :ref="widget.id"/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<component :is="'mk-hw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/>
|
||||
<component :is="'mkw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
@ -67,10 +67,10 @@
|
||||
<div ref="right" data-place="right">
|
||||
<template v-for="widget in rightWidgets">
|
||||
<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)">
|
||||
<component :is="'mk-hw-' + widget.name" :widget="widget" :ref="widget.id"/>
|
||||
<component :is="'mkw-' + widget.name" :widget="widget" :ref="widget.id"/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<component :is="'mk-hw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/>
|
||||
<component :is="'mkw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -32,6 +32,13 @@ import driveFile from './drive-file.vue';
|
||||
import driveFolder from './drive-folder.vue';
|
||||
import driveNavFolder from './drive-nav-folder.vue';
|
||||
import contextMenuMenu from './context-menu-menu.vue';
|
||||
import wNav from './widgets/nav.vue';
|
||||
import wCalendar from './widgets/calendar.vue';
|
||||
import wPhotoStream from './widgets/photo-stream.vue';
|
||||
import wSlideshow from './widgets/slideshow.vue';
|
||||
import wTips from './widgets/tips.vue';
|
||||
import wDonation from './widgets/donation.vue';
|
||||
import wNotifications from './widgets/notifications.vue';
|
||||
|
||||
Vue.component('mk-ui', ui);
|
||||
Vue.component('mk-ui-header', uiHeader);
|
||||
@ -65,3 +72,10 @@ Vue.component('mk-drive-file', driveFile);
|
||||
Vue.component('mk-drive-folder', driveFolder);
|
||||
Vue.component('mk-drive-nav-folder', driveNavFolder);
|
||||
Vue.component('context-menu-menu', contextMenuMenu);
|
||||
Vue.component('mkw-nav', wNav);
|
||||
Vue.component('mkw-calendar', wCalendar);
|
||||
Vue.component('mkw-photo-stream', wPhotoStream);
|
||||
Vue.component('mkw-slideshoe', wSlideshow);
|
||||
Vue.component('mkw-tips', wTips);
|
||||
Vue.component('mkw-donation', wDonation);
|
||||
Vue.component('mkw-notifications', wNotifications);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<mk-window ref="window" width='500px' height='560px' @closed="$destroy">
|
||||
<mk-window ref="window" width="500px" height="560px" @closed="$destroy">
|
||||
<span slot="header" :class="$style.header">%fa:comments%メッセージ</span>
|
||||
<mk-messaging :class="$style.content" @navigate="navigate"/>
|
||||
</mk-window>
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkMessagingRoomWindow from './messaging-room-window.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
methods: {
|
||||
navigate(user) {
|
||||
|
@ -7,6 +7,11 @@
|
||||
</mk-window>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
export default Vue.extend({});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" module>
|
||||
.header
|
||||
> [data-fa]
|
||||
|
@ -33,6 +33,7 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkSettingsWindow from './settings-window.vue';
|
||||
import MkDriveWindow from './drive-window.vue';
|
||||
import contains from '../../../common/scripts/contains';
|
||||
import signout from '../../../common/scripts/signout';
|
||||
|
||||
@ -69,8 +70,7 @@ export default Vue.extend({
|
||||
},
|
||||
drive() {
|
||||
this.close();
|
||||
// TODO
|
||||
//document.body.appendChild(new MkDriveWindow().$mount().$el);
|
||||
document.body.appendChild(new MkDriveWindow().$mount().$el);
|
||||
},
|
||||
settings() {
|
||||
this.close();
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkMessagingWindow from './messaging-window.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
@ -76,8 +77,7 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
messaging() {
|
||||
// TODO
|
||||
//document.body.appendChild(new MkMessagingWindow().$mount().$el);
|
||||
document.body.appendChild(new MkMessagingWindow().$mount().$el);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
192
src/web/app/desktop/views/components/widgets/calendar.vue
Normal file
192
src/web/app/desktop/views/components/widgets/calendar.vue
Normal file
@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div class="mkw-calendar"
|
||||
:data-melt="props.design == 1"
|
||||
:data-special="special"
|
||||
>
|
||||
<div class="calendar" :data-is-holiday="isHoliday">
|
||||
<p class="month-and-year">
|
||||
<span class="year">{{ year }}年</span>
|
||||
<span class="month">{{ month }}月</span>
|
||||
</p>
|
||||
<p class="day">{{ day }}日</p>
|
||||
<p class="week-day">{{ weekDay }}曜日</p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div>
|
||||
<p>今日:<b>{{ dayP.toFixed(1) }}%</b></p>
|
||||
<div class="meter">
|
||||
<div class="val" :style="{ width: `${dayP}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>今月:<b>{{ monthP.toFixed(1) }}%</b></p>
|
||||
<div class="meter">
|
||||
<div class="val" :style="{ width: `${monthP}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>今年:<b>{{ yearP.toFixed(1) }}%</b></p>
|
||||
<div class="meter">
|
||||
<div class="val" :style="{ width: `${yearP}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'calendar',
|
||||
props: {
|
||||
design: 0
|
||||
}
|
||||
}).extend({
|
||||
data() {
|
||||
return {
|
||||
now: new Date(),
|
||||
year: null,
|
||||
month: null,
|
||||
day: null,
|
||||
weekDay: null,
|
||||
yearP: null,
|
||||
dayP: null,
|
||||
monthP: null,
|
||||
isHoliday: null,
|
||||
special: null,
|
||||
clock: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.tick();
|
||||
this.clock = setInterval(this.tick, 1000);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.clock);
|
||||
},
|
||||
methods: {
|
||||
func() {
|
||||
if (this.props.design == 2) {
|
||||
this.props.design = 0;
|
||||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
},
|
||||
tick() {
|
||||
const now = new Date();
|
||||
const nd = now.getDate();
|
||||
const nm = now.getMonth();
|
||||
const ny = now.getFullYear();
|
||||
|
||||
this.year = ny;
|
||||
this.month = nm + 1;
|
||||
this.day = nd;
|
||||
this.weekDay = ['日', '月', '火', '水', '木', '金', '土'][now.getDay()];
|
||||
|
||||
const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime();
|
||||
const dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/;
|
||||
const monthNumer = now.getTime() - new Date(ny, nm, 1).getTime();
|
||||
const monthDenom = new Date(ny, nm + 1, 1).getTime() - new Date(ny, nm, 1).getTime();
|
||||
const yearNumer = now.getTime() - new Date(ny, 0, 1).getTime();
|
||||
const yearDenom = new Date(ny + 1, 0, 1).getTime() - new Date(ny, 0, 1).getTime();
|
||||
|
||||
this.dayP = dayNumer / dayDenom * 100;
|
||||
this.monthP = monthNumer / monthDenom * 100;
|
||||
this.yearP = yearNumer / yearDenom * 100;
|
||||
|
||||
this.isHoliday = now.getDay() == 0 || now.getDay() == 6;
|
||||
|
||||
this.special =
|
||||
nm == 0 && nd == 1 ? 'on-new-years-day' :
|
||||
false;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-calendar
|
||||
padding 16px 0
|
||||
color #777
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
&[data-special='on-new-years-day']
|
||||
border-color #ef95a0
|
||||
|
||||
&[data-melt]
|
||||
background transparent
|
||||
border none
|
||||
|
||||
&:after
|
||||
content ""
|
||||
display block
|
||||
clear both
|
||||
|
||||
> .calendar
|
||||
float left
|
||||
width 60%
|
||||
text-align center
|
||||
|
||||
&[data-is-holiday]
|
||||
> .day
|
||||
color #ef95a0
|
||||
|
||||
> p
|
||||
margin 0
|
||||
line-height 18px
|
||||
font-size 14px
|
||||
|
||||
> span
|
||||
margin 0 4px
|
||||
|
||||
> .day
|
||||
margin 10px 0
|
||||
line-height 32px
|
||||
font-size 28px
|
||||
|
||||
> .info
|
||||
display block
|
||||
float left
|
||||
width 40%
|
||||
padding 0 16px 0 0
|
||||
|
||||
> div
|
||||
margin-bottom 8px
|
||||
|
||||
&:last-child
|
||||
margin-bottom 4px
|
||||
|
||||
> p
|
||||
margin 0 0 2px 0
|
||||
font-size 12px
|
||||
line-height 18px
|
||||
color #888
|
||||
|
||||
> b
|
||||
margin-left 2px
|
||||
|
||||
> .meter
|
||||
width 100%
|
||||
overflow hidden
|
||||
background #eee
|
||||
border-radius 8px
|
||||
|
||||
> .val
|
||||
height 4px
|
||||
background $theme-color
|
||||
|
||||
&:nth-child(1)
|
||||
> .meter > .val
|
||||
background #f7796c
|
||||
|
||||
&:nth-child(2)
|
||||
> .meter > .val
|
||||
background #a1de41
|
||||
|
||||
&:nth-child(3)
|
||||
> .meter > .val
|
||||
background #41ddde
|
||||
|
||||
</style>
|
45
src/web/app/desktop/views/components/widgets/donation.vue
Normal file
45
src/web/app/desktop/views/components/widgets/donation.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div class="mkw-donation">
|
||||
<article>
|
||||
<h1>%fa:heart%%i18n:desktop.tags.mk-donation-home-widget.title%</h1>
|
||||
<p>
|
||||
{{ '%i18n:desktop.tags.mk-donation-home-widget.text%'.substr(0, '%i18n:desktop.tags.mk-donation-home-widget.text%'.indexOf('{')) }}
|
||||
<a href="/syuilo" data-user-preview="@syuilo">@syuilo</a>
|
||||
{{ '%i18n:desktop.tags.mk-donation-home-widget.text%'.substr('%i18n:desktop.tags.mk-donation-home-widget.text%'.indexOf('}') + 1) }}
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'donation'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-donation
|
||||
background #fff
|
||||
border solid 1px #ead8bb
|
||||
border-radius 6px
|
||||
|
||||
> article
|
||||
padding 20px
|
||||
|
||||
> h1
|
||||
margin 0 0 5px 0
|
||||
font-size 1em
|
||||
color #888
|
||||
|
||||
> [data-fa]
|
||||
margin-right 0.25em
|
||||
|
||||
> p
|
||||
display block
|
||||
z-index 1
|
||||
margin 0
|
||||
font-size 0.8em
|
||||
color #999
|
||||
|
||||
</style>
|
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../define-widget';
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'messaging',
|
||||
props: {
|
||||
|
29
src/web/app/desktop/views/components/widgets/nav.vue
Normal file
29
src/web/app/desktop/views/components/widgets/nav.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div class="mkw-nav">
|
||||
<mk-nav-links/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'nav'
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-nav
|
||||
padding 16px
|
||||
font-size 12px
|
||||
color #aaa
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
a
|
||||
color #999
|
||||
|
||||
i
|
||||
color #ccc
|
||||
|
||||
</style>
|
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="mkw-notifications">
|
||||
<template v-if="!props.compact">
|
||||
<p class="title">%fa:R bell%%i18n:desktop.tags.mk-notifications-home-widget.title%</p>
|
||||
<button @click="settings" title="%i18n:desktop.tags.mk-notifications-home-widget.settings%">%fa:cog%</button>
|
||||
</template>
|
||||
<mk-notifications/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'notifications',
|
||||
props: {
|
||||
compact: false
|
||||
}
|
||||
}).extend({
|
||||
methods: {
|
||||
settings() {
|
||||
alert('not implemented yet');
|
||||
},
|
||||
func() {
|
||||
this.props.compact = !this.props.compact;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-notifications
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
> .title
|
||||
z-index 1
|
||||
margin 0
|
||||
padding 0 16px
|
||||
line-height 42px
|
||||
font-size 0.9em
|
||||
font-weight bold
|
||||
color #888
|
||||
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
> button
|
||||
position absolute
|
||||
z-index 2
|
||||
top 0
|
||||
right 0
|
||||
padding 0
|
||||
width 42px
|
||||
font-size 0.9em
|
||||
line-height 42px
|
||||
color #ccc
|
||||
|
||||
&:hover
|
||||
color #aaa
|
||||
|
||||
&:active
|
||||
color #999
|
||||
|
||||
> .mk-notifications
|
||||
max-height 300px
|
||||
overflow auto
|
||||
|
||||
</style>
|
122
src/web/app/desktop/views/components/widgets/photo-stream.vue
Normal file
122
src/web/app/desktop/views/components/widgets/photo-stream.vue
Normal file
@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="mkw-photo-stream" :data-melt="props.design == 2">
|
||||
<p class="title" v-if="props.design == 0">%fa:camera%%i18n:desktop.tags.mk-photo-stream-home-widget.title%</p>
|
||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||
<div class="stream" v-if="!fetching && images.length > 0">
|
||||
<div v-for="image in images" :key="image.id" class="img" :style="`background-image: url(${image.url}?thumbnail&size=256)`"></div>
|
||||
</div>
|
||||
<p class="empty" v-if="!fetching && images.length == 0">%i18n:desktop.tags.mk-photo-stream-home-widget.no-photos%</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'photo-stream',
|
||||
props: {
|
||||
design: 0
|
||||
}
|
||||
}).extend({
|
||||
data() {
|
||||
return {
|
||||
images: [],
|
||||
fetching: true,
|
||||
connection: null,
|
||||
connectionId: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.connection = (this as any).os.stream.getConnection();
|
||||
this.connectionId = (this as any).os.stream.use();
|
||||
|
||||
this.connection.on('drive_file_created', this.onDriveFileCreated);
|
||||
|
||||
(this as any).api('drive/stream', {
|
||||
type: 'image/*',
|
||||
limit: 9
|
||||
}).then(images => {
|
||||
this.fetching = false;
|
||||
this.images = images;
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.connection.off('drive_file_created', this.onDriveFileCreated);
|
||||
(this as any).os.stream.dispose(this.connectionId);
|
||||
},
|
||||
methods: {
|
||||
onDriveFileCreated(file) {
|
||||
if (/^image\/.+$/.test(file.type)) {
|
||||
this.images.unshift(file);
|
||||
if (this.images.length > 9) this.images.pop();
|
||||
}
|
||||
},
|
||||
func() {
|
||||
if (this.props.design == 2) {
|
||||
this.props.design = 0;
|
||||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-photo-stream
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
&[data-melt]
|
||||
background transparent !important
|
||||
border none !important
|
||||
|
||||
> .stream
|
||||
padding 0
|
||||
|
||||
> .img
|
||||
border solid 4px transparent
|
||||
border-radius 8px
|
||||
|
||||
> .title
|
||||
z-index 1
|
||||
margin 0
|
||||
padding 0 16px
|
||||
line-height 42px
|
||||
font-size 0.9em
|
||||
font-weight bold
|
||||
color #888
|
||||
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
> .stream
|
||||
display -webkit-flex
|
||||
display -moz-flex
|
||||
display -ms-flex
|
||||
display flex
|
||||
justify-content center
|
||||
flex-wrap wrap
|
||||
padding 8px
|
||||
|
||||
> .img
|
||||
flex 1 1 33%
|
||||
width 33%
|
||||
height 80px
|
||||
background-position center center
|
||||
background-size cover
|
||||
border solid 2px transparent
|
||||
border-radius 4px
|
||||
|
||||
> .fetching
|
||||
> .empty
|
||||
margin 0
|
||||
padding 16px
|
||||
text-align center
|
||||
color #aaa
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
</style>
|
125
src/web/app/desktop/views/components/widgets/profile.vue
Normal file
125
src/web/app/desktop/views/components/widgets/profile.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="mkw-profile"
|
||||
:data-compact="props.design == 1 || props.design == 2"
|
||||
:data-melt="props.design == 2"
|
||||
>
|
||||
<div class="banner"
|
||||
style={ I.banner_url ? 'background-image: url(' + I.banner_url + '?thumbnail&size=256)' : '' }
|
||||
title="クリックでバナー編集"
|
||||
@click="wapi_setBanner"
|
||||
></div>
|
||||
<img class="avatar"
|
||||
src={ I.avatar_url + '?thumbnail&size=96' }
|
||||
@click="wapi_setAvatar"
|
||||
alt="avatar"
|
||||
title="クリックでアバター編集"
|
||||
v-user-preview={ I.id }
|
||||
/>
|
||||
<a class="name" href={ '/' + I.username }>{ I.name }</a>
|
||||
<p class="username">@{ I.username }</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'profile',
|
||||
props: {
|
||||
design: 0
|
||||
}
|
||||
}).extend({
|
||||
methods: {
|
||||
func() {
|
||||
if (this.props.design == 2) {
|
||||
this.props.design = 0;
|
||||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-profile
|
||||
overflow hidden
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
&[data-compact]
|
||||
> .banner:before
|
||||
content ""
|
||||
display block
|
||||
width 100%
|
||||
height 100%
|
||||
background rgba(0, 0, 0, 0.5)
|
||||
|
||||
> .avatar
|
||||
top ((100px - 58px) / 2)
|
||||
left ((100px - 58px) / 2)
|
||||
border none
|
||||
border-radius 100%
|
||||
box-shadow 0 0 16px rgba(0, 0, 0, 0.5)
|
||||
|
||||
> .name
|
||||
position absolute
|
||||
top 0
|
||||
left 92px
|
||||
margin 0
|
||||
line-height 100px
|
||||
color #fff
|
||||
text-shadow 0 0 8px rgba(0, 0, 0, 0.5)
|
||||
|
||||
> .username
|
||||
display none
|
||||
|
||||
&[data-melt]
|
||||
background transparent !important
|
||||
border none !important
|
||||
|
||||
> .banner
|
||||
visibility hidden
|
||||
|
||||
> .avatar
|
||||
box-shadow none
|
||||
|
||||
> .name
|
||||
color #666
|
||||
text-shadow none
|
||||
|
||||
> .banner
|
||||
height 100px
|
||||
background-color #f5f5f5
|
||||
background-size cover
|
||||
background-position center
|
||||
cursor pointer
|
||||
|
||||
> .avatar
|
||||
display block
|
||||
position absolute
|
||||
top 76px
|
||||
left 16px
|
||||
width 58px
|
||||
height 58px
|
||||
margin 0
|
||||
border solid 3px #fff
|
||||
border-radius 8px
|
||||
vertical-align bottom
|
||||
cursor pointer
|
||||
|
||||
> .name
|
||||
display block
|
||||
margin 10px 0 0 84px
|
||||
line-height 16px
|
||||
font-weight bold
|
||||
color #555
|
||||
|
||||
> .username
|
||||
display block
|
||||
margin 4px 0 8px 84px
|
||||
line-height 16px
|
||||
font-size 0.9em
|
||||
color #999
|
||||
|
||||
</style>
|
153
src/web/app/desktop/views/components/widgets/slideshow.vue
Normal file
153
src/web/app/desktop/views/components/widgets/slideshow.vue
Normal file
@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<div class="mkw-slideshow">
|
||||
<div @click="choose">
|
||||
<p v-if="data.folder === undefined">クリックしてフォルダを指定してください</p>
|
||||
<p v-if="data.folder !== undefined && images.length == 0 && !fetching">このフォルダには画像がありません</p>
|
||||
<div ref="slideA" class="slide a"></div>
|
||||
<div ref="slideB" class="slide b"></div>
|
||||
</div>
|
||||
<button @click="resize">%fa:expand%</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import * as anime from 'animejs';
|
||||
import define from '../../../../common/define-widget';
|
||||
export default define({
|
||||
name: 'slideshow',
|
||||
props: {
|
||||
folder: undefined,
|
||||
size: 0
|
||||
}
|
||||
}).extend({
|
||||
data() {
|
||||
return {
|
||||
images: [],
|
||||
fetching: true,
|
||||
clock: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.applySize();
|
||||
});
|
||||
|
||||
if (this.props.folder !== undefined) {
|
||||
this.fetch();
|
||||
}
|
||||
|
||||
this.clock = setInterval(this.change, 10000);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.clock);
|
||||
},
|
||||
methods: {
|
||||
applySize() {
|
||||
let h;
|
||||
|
||||
if (this.props.size == 1) {
|
||||
h = 250;
|
||||
} else {
|
||||
h = 170;
|
||||
}
|
||||
|
||||
this.$el.style.height = `${h}px`;
|
||||
},
|
||||
resize() {
|
||||
if (this.props.size == 1) {
|
||||
this.props.size = 0;
|
||||
} else {
|
||||
this.props.size++;
|
||||
}
|
||||
|
||||
this.applySize();
|
||||
},
|
||||
change() {
|
||||
if (this.images.length == 0) return;
|
||||
|
||||
const index = Math.floor(Math.random() * this.images.length);
|
||||
const img = `url(${ this.images[index].url }?thumbnail&size=1024)`;
|
||||
|
||||
(this.$refs.slideB as any).style.backgroundImage = img;
|
||||
|
||||
anime({
|
||||
targets: this.$refs.slideB,
|
||||
opacity: 1,
|
||||
duration: 1000,
|
||||
easing: 'linear',
|
||||
complete: () => {
|
||||
(this.$refs.slideA as any).style.backgroundImage = img;
|
||||
anime({
|
||||
targets: this.$refs.slideB,
|
||||
opacity: 0,
|
||||
duration: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
fetch() {
|
||||
this.fetching = true;
|
||||
|
||||
(this as any).api('drive/files', {
|
||||
folder_id: this.props.folder,
|
||||
type: 'image/*',
|
||||
limit: 100
|
||||
}).then(images => {
|
||||
this.fetching = false;
|
||||
this.images = images;
|
||||
(this.$refs.slideA as any).style.backgroundImage = '';
|
||||
(this.$refs.slideB as any).style.backgroundImage = '';
|
||||
this.change();
|
||||
});
|
||||
},
|
||||
choose() {
|
||||
(this as any).apis.chooseDriveFolder().then(folder => {
|
||||
this.props.folder = folder ? folder.id : null;
|
||||
this.fetch();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-slideshow
|
||||
overflow hidden
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
&:hover > button
|
||||
display block
|
||||
|
||||
> button
|
||||
position absolute
|
||||
left 0
|
||||
bottom 0
|
||||
display none
|
||||
padding 4px
|
||||
font-size 24px
|
||||
color #fff
|
||||
text-shadow 0 0 8px #000
|
||||
|
||||
> div
|
||||
width 100%
|
||||
height 100%
|
||||
cursor pointer
|
||||
|
||||
> *
|
||||
pointer-events none
|
||||
|
||||
> .slide
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
width 100%
|
||||
height 100%
|
||||
background-size cover
|
||||
background-position center
|
||||
|
||||
&.b
|
||||
opacity 0
|
||||
|
||||
</style>
|
108
src/web/app/desktop/views/components/widgets/tips.vue
Normal file
108
src/web/app/desktop/views/components/widgets/tips.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="mkw-tips">
|
||||
<p ref="tip">%fa:R lightbulb%<span v-html="tip"></span></p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import * as anime from 'animejs';
|
||||
import define from '../../../../common/define-widget';
|
||||
|
||||
const tips = [
|
||||
'<kbd>t</kbd>でタイムラインにフォーカスできます',
|
||||
'<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます',
|
||||
'投稿フォームにはファイルをドラッグ&ドロップできます',
|
||||
'投稿フォームにクリップボードにある画像データをペーストできます',
|
||||
'ドライブにファイルをドラッグ&ドロップしてアップロードできます',
|
||||
'ドライブでファイルをドラッグしてフォルダ移動できます',
|
||||
'ドライブでフォルダをドラッグしてフォルダ移動できます',
|
||||
'ホームは設定からカスタマイズできます',
|
||||
'MisskeyはMIT Licenseです',
|
||||
'タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます',
|
||||
'投稿の ... をクリックして、投稿をユーザーページにピン留めできます',
|
||||
'ドライブの容量は(デフォルトで)1GBです',
|
||||
'投稿に添付したファイルは全てドライブに保存されます',
|
||||
'ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます',
|
||||
'タイムライン上部にもウィジェットを設置できます',
|
||||
'投稿をダブルクリックすると詳細が見れます',
|
||||
'「**」でテキストを囲むと**強調表示**されます',
|
||||
'チャンネルウィジェットを利用すると、よく利用するチャンネルを素早く確認できます',
|
||||
'いくつかのウィンドウはブラウザの外に切り離すことができます',
|
||||
'カレンダーウィジェットのパーセンテージは、経過の割合を示しています',
|
||||
'APIを利用してbotの開発なども行えます',
|
||||
'MisskeyはLINEを通じてでも利用できます',
|
||||
'まゆかわいいよまゆ',
|
||||
'Misskeyは2014年にサービスを開始しました',
|
||||
'対応ブラウザではMisskeyを開いていなくても通知を受け取れます'
|
||||
]
|
||||
|
||||
export default define({
|
||||
name: 'tips'
|
||||
}).extend({
|
||||
data() {
|
||||
return {
|
||||
tip: null,
|
||||
clock: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.set();
|
||||
});
|
||||
|
||||
this.clock = setInterval(this.change, 20000);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.clock);
|
||||
},
|
||||
methods: {
|
||||
set() {
|
||||
this.tip = tips[Math.floor(Math.random() * tips.length)];
|
||||
},
|
||||
change() {
|
||||
anime({
|
||||
targets: this.$refs.tip,
|
||||
opacity: 0,
|
||||
duration: 500,
|
||||
easing: 'linear',
|
||||
complete: this.set
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
anime({
|
||||
targets: this.$refs.tip,
|
||||
opacity: 1,
|
||||
duration: 500,
|
||||
easing: 'linear'
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-tips
|
||||
overflow visible !important
|
||||
|
||||
> p
|
||||
display block
|
||||
margin 0
|
||||
padding 0 12px
|
||||
text-align center
|
||||
font-size 0.7em
|
||||
color #999
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
kbd
|
||||
display inline
|
||||
padding 0 6px
|
||||
margin 0 2px
|
||||
font-size 1em
|
||||
font-family inherit
|
||||
border solid 1px #999
|
||||
border-radius 2px
|
||||
|
||||
</style>
|
Reference in New Issue
Block a user