wip
This commit is contained in:
parent
b47fd29535
commit
ca60469262
@ -2,7 +2,7 @@ import Vue from 'vue';
|
||||
|
||||
export default function<T extends object>(data: {
|
||||
name: string;
|
||||
props: T;
|
||||
props?: T;
|
||||
}) {
|
||||
return Vue.extend({
|
||||
props: {
|
||||
@ -26,7 +26,7 @@ export default function<T extends object>(data: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
props: data.props
|
||||
props: data.props || {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
|
192
src/web/app/common/views/components/widgets/calendar.vue
Normal file
192
src/web/app/common/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 '../../../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/common/views/components/widgets/donation.vue
Normal file
45
src/web/app/common/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 '../../../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>
|
59
src/web/app/common/views/components/widgets/messaging.vue
Normal file
59
src/web/app/common/views/components/widgets/messaging.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="mkw-messaging">
|
||||
<p class="title" v-if="props.design == 0">%fa:comments%%i18n:desktop.tags.mk-messaging-home-widget.title%</p>
|
||||
<mk-messaging ref="index" compact @navigate="navigate"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import define from '../../../define-widget';
|
||||
export default define({
|
||||
name: 'messaging',
|
||||
props: {
|
||||
design: 0
|
||||
}
|
||||
}).extend({
|
||||
methods: {
|
||||
navigate(user) {
|
||||
if (this.platform == 'desktop') {
|
||||
this.wapi_openMessagingRoomWindow(user);
|
||||
} else {
|
||||
// TODO: open room page in new tab
|
||||
}
|
||||
},
|
||||
func() {
|
||||
if (this.props.design == 1) {
|
||||
this.props.design = 0;
|
||||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.mkw-messaging
|
||||
overflow hidden
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
> .title
|
||||
z-index 2
|
||||
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
|
||||
|
||||
> mk-messaging
|
||||
max-height 250px
|
||||
overflow auto
|
||||
|
||||
</style>
|
29
src/web/app/common/views/components/widgets/nav.vue
Normal file
29
src/web/app/common/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 '../../../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>
|
122
src/web/app/common/views/components/widgets/photo-stream.vue
Normal file
122
src/web/app/common/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 '../../../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.$root.$data.os.stream.getConnection();
|
||||
this.connectionId = this.$root.$data.os.stream.use();
|
||||
|
||||
this.connection.on('drive_file_created', this.onDriveFileCreated);
|
||||
|
||||
this.$root.$data.os.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.$root.$data.os.stream.dispose(this.connectionId);
|
||||
},
|
||||
methods: {
|
||||
onStreamDriveFileCreated(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>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mkw-profile"
|
||||
data-compact={ data.design == 1 || data.design == 2 }
|
||||
data-melt={ data.design == 2 }
|
||||
: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)' : '' }
|
||||
|
154
src/web/app/common/views/components/widgets/slideshow.vue
Normal file
154
src/web/app/common/views/components/widgets/slideshow.vue
Normal file
@ -0,0 +1,154 @@
|
||||
<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 Vue from 'vue';
|
||||
import * as anime from 'animejs';
|
||||
import define from '../../../define-widget';
|
||||
export default define({
|
||||
name: 'slideshow',
|
||||
props: {
|
||||
folder: undefined,
|
||||
size: 0
|
||||
}
|
||||
}).extend({
|
||||
data() {
|
||||
return {
|
||||
images: [],
|
||||
fetching: true,
|
||||
clock: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
Vue.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.$root.$data.os.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.wapi_selectDriveFolder().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>
|
109
src/web/app/common/views/components/widgets/tips.vue
Normal file
109
src/web/app/common/views/components/widgets/tips.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="mkw-tips">
|
||||
<p ref="tip">%fa:R lightbulb%<span v-html="tip"></span></p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import * as anime from 'animejs';
|
||||
import define from '../../../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() {
|
||||
Vue.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>
|
@ -1,167 +0,0 @@
|
||||
<mk-calendar-home-widget data-melt={ data.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>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
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>
|
||||
<script lang="typescript">
|
||||
this.data = {
|
||||
design: 0
|
||||
};
|
||||
|
||||
this.mixin('widget');
|
||||
|
||||
this.draw = () => {
|
||||
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()];
|
||||
|
||||
this.dayNumer = now - new Date(ny, nm, nd);
|
||||
this.dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/;
|
||||
this.monthNumer = now - new Date(ny, nm, 1);
|
||||
this.monthDenom = new Date(ny, nm + 1, 1) - new Date(ny, nm, 1);
|
||||
this.yearNumer = now - new Date(ny, 0, 1);
|
||||
this.yearDenom = new Date(ny + 1, 0, 1) - new Date(ny, 0, 1);
|
||||
|
||||
this.dayP = this.dayNumer / this.dayDenom * 100;
|
||||
this.monthP = this.monthNumer / this.monthDenom * 100;
|
||||
this.yearP = this.yearNumer / this.yearDenom * 100;
|
||||
|
||||
this.isHoliday = now.getDay() == 0 || now.getDay() == 6;
|
||||
|
||||
this.special =
|
||||
nm == 0 && nd == 1 ? 'on-new-years-day' :
|
||||
false;
|
||||
|
||||
this.update();
|
||||
};
|
||||
|
||||
this.draw();
|
||||
|
||||
this.on('mount', () => {
|
||||
this.clock = setInterval(this.draw, 1000);
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
clearInterval(this.clock);
|
||||
});
|
||||
|
||||
this.func = () => {
|
||||
if (++this.data.design == 2) this.data.design = 0;
|
||||
this.save();
|
||||
};
|
||||
</script>
|
||||
</mk-calendar-home-widget>
|
@ -1,36 +0,0 @@
|
||||
<mk-donation-home-widget>
|
||||
<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>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
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>
|
||||
<script lang="typescript">
|
||||
this.mixin('widget');
|
||||
this.mixin('user-preview');
|
||||
</script>
|
||||
</mk-donation-home-widget>
|
@ -1,52 +0,0 @@
|
||||
<mk-messaging-home-widget>
|
||||
<template v-if="data.design == 0">
|
||||
<p class="title">%fa:comments%%i18n:desktop.tags.mk-messaging-home-widget.title%</p>
|
||||
</template>
|
||||
<mk-messaging ref="index" compact={ true }/>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
overflow hidden
|
||||
background #fff
|
||||
border solid 1px rgba(0, 0, 0, 0.075)
|
||||
border-radius 6px
|
||||
|
||||
> .title
|
||||
z-index 2
|
||||
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
|
||||
|
||||
> mk-messaging
|
||||
max-height 250px
|
||||
overflow auto
|
||||
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.data = {
|
||||
design: 0
|
||||
};
|
||||
|
||||
this.mixin('widget');
|
||||
|
||||
this.on('mount', () => {
|
||||
this.$refs.index.on('navigate-user', user => {
|
||||
riot.mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), {
|
||||
user: user
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.func = () => {
|
||||
if (++this.data.design == 2) this.data.design = 0;
|
||||
this.save();
|
||||
};
|
||||
</script>
|
||||
</mk-messaging-home-widget>
|
@ -1,23 +0,0 @@
|
||||
<mk-nav-home-widget>
|
||||
<mk-nav-links/>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
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>
|
||||
<script lang="typescript">
|
||||
this.mixin('widget');
|
||||
</script>
|
||||
</mk-nav-home-widget>
|
@ -1,118 +0,0 @@
|
||||
<mk-photo-stream-home-widget data-melt={ data.design == 2 }>
|
||||
<template v-if="data.design == 0">
|
||||
<p class="title">%fa:camera%%i18n:desktop.tags.mk-photo-stream-home-widget.title%</p>
|
||||
</template>
|
||||
<p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||
<div class="stream" v-if="!initializing && images.length > 0">
|
||||
<template each={ image in images }>
|
||||
<div class="img" style={ 'background-image: url(' + image.url + '?thumbnail&size=256)' }></div>
|
||||
</template>
|
||||
</div>
|
||||
<p class="empty" v-if="!initializing && images.length == 0">%i18n:desktop.tags.mk-photo-stream-home-widget.no-photos%</p>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
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
|
||||
|
||||
> .initializing
|
||||
> .empty
|
||||
margin 0
|
||||
padding 16px
|
||||
text-align center
|
||||
color #aaa
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
|
||||
</style>
|
||||
<script lang="typescript">
|
||||
this.data = {
|
||||
design: 0
|
||||
};
|
||||
|
||||
this.mixin('widget');
|
||||
|
||||
this.mixin('stream');
|
||||
this.connection = this.stream.getConnection();
|
||||
this.connectionId = this.stream.use();
|
||||
|
||||
this.images = [];
|
||||
this.initializing = true;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.connection.on('drive_file_created', this.onStreamDriveFileCreated);
|
||||
|
||||
this.api('drive/stream', {
|
||||
type: 'image/*',
|
||||
limit: 9
|
||||
}).then(images => {
|
||||
this.update({
|
||||
initializing: false,
|
||||
images: images
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
this.connection.off('drive_file_created', this.onStreamDriveFileCreated);
|
||||
this.stream.dispose(this.connectionId);
|
||||
});
|
||||
|
||||
this.onStreamDriveFileCreated = file => {
|
||||
if (/^image\/.+$/.test(file.type)) {
|
||||
this.images.unshift(file);
|
||||
if (this.images.length > 9) this.images.pop();
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
|
||||
this.func = () => {
|
||||
if (++this.data.design == 3) this.data.design = 0;
|
||||
this.save();
|
||||
};
|
||||
</script>
|
||||
</mk-photo-stream-home-widget>
|
@ -1,151 +0,0 @@
|
||||
<mk-slideshow-home-widget>
|
||||
<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>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
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>
|
||||
<script lang="typescript">
|
||||
import * as anime from 'animejs';
|
||||
|
||||
this.data = {
|
||||
folder: undefined,
|
||||
size: 0
|
||||
};
|
||||
|
||||
this.mixin('widget');
|
||||
|
||||
this.images = [];
|
||||
this.fetching = true;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.applySize();
|
||||
|
||||
if (this.data.folder !== undefined) {
|
||||
this.fetch();
|
||||
}
|
||||
|
||||
this.clock = setInterval(this.change, 10000);
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
clearInterval(this.clock);
|
||||
});
|
||||
|
||||
this.applySize = () => {
|
||||
let h;
|
||||
|
||||
if (this.data.size == 1) {
|
||||
h = 250;
|
||||
} else {
|
||||
h = 170;
|
||||
}
|
||||
|
||||
this.root.style.height = `${h}px`;
|
||||
};
|
||||
|
||||
this.resize = () => {
|
||||
this.data.size++;
|
||||
if (this.data.size == 2) this.data.size = 0;
|
||||
|
||||
this.applySize();
|
||||
this.save();
|
||||
};
|
||||
|
||||
this.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.style.backgroundImage = img;
|
||||
|
||||
anime({
|
||||
targets: this.$refs.slideB,
|
||||
opacity: 1,
|
||||
duration: 1000,
|
||||
easing: 'linear',
|
||||
complete: () => {
|
||||
this.$refs.slideA.style.backgroundImage = img;
|
||||
anime({
|
||||
targets: this.$refs.slideB,
|
||||
opacity: 0,
|
||||
duration: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.fetch = () => {
|
||||
this.update({
|
||||
fetching: true
|
||||
});
|
||||
|
||||
this.api('drive/files', {
|
||||
folder_id: this.data.folder,
|
||||
type: 'image/*',
|
||||
limit: 100
|
||||
}).then(images => {
|
||||
this.update({
|
||||
fetching: false,
|
||||
images: images
|
||||
});
|
||||
this.$refs.slideA.style.backgroundImage = '';
|
||||
this.$refs.slideB.style.backgroundImage = '';
|
||||
this.change();
|
||||
});
|
||||
};
|
||||
|
||||
this.choose = () => {
|
||||
const i = riot.mount(document.body.appendChild(document.createElement('mk-select-folder-from-drive-window')))[0];
|
||||
i.one('selected', folder => {
|
||||
this.data.folder = folder ? folder.id : null;
|
||||
this.fetch();
|
||||
this.save();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</mk-slideshow-home-widget>
|
@ -1,94 +0,0 @@
|
||||
<mk-tips-home-widget>
|
||||
<p ref="tip">%fa:R lightbulb%<span ref="text"></span></p>
|
||||
<style lang="stylus" scoped>
|
||||
:scope
|
||||
display block
|
||||
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>
|
||||
<script lang="typescript">
|
||||
import * as anime from 'animejs';
|
||||
|
||||
this.mixin('widget');
|
||||
|
||||
this.tips = [
|
||||
'<kbd>t</kbd>でタイムラインにフォーカスできます',
|
||||
'<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます',
|
||||
'投稿フォームにはファイルをドラッグ&ドロップできます',
|
||||
'投稿フォームにクリップボードにある画像データをペーストできます',
|
||||
'ドライブにファイルをドラッグ&ドロップしてアップロードできます',
|
||||
'ドライブでファイルをドラッグしてフォルダ移動できます',
|
||||
'ドライブでフォルダをドラッグしてフォルダ移動できます',
|
||||
'ホームは設定からカスタマイズできます',
|
||||
'MisskeyはMIT Licenseです',
|
||||
'タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます',
|
||||
'投稿の ... をクリックして、投稿をユーザーページにピン留めできます',
|
||||
'ドライブの容量は(デフォルトで)1GBです',
|
||||
'投稿に添付したファイルは全てドライブに保存されます',
|
||||
'ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます',
|
||||
'タイムライン上部にもウィジェットを設置できます',
|
||||
'投稿をダブルクリックすると詳細が見れます',
|
||||
'「**」でテキストを囲むと**強調表示**されます',
|
||||
'チャンネルウィジェットを利用すると、よく利用するチャンネルを素早く確認できます',
|
||||
'いくつかのウィンドウはブラウザの外に切り離すことができます',
|
||||
'カレンダーウィジェットのパーセンテージは、経過の割合を示しています',
|
||||
'APIを利用してbotの開発なども行えます',
|
||||
'MisskeyはLINEを通じてでも利用できます',
|
||||
'まゆかわいいよまゆ',
|
||||
'Misskeyは2014年にサービスを開始しました',
|
||||
'対応ブラウザではMisskeyを開いていなくても通知を受け取れます'
|
||||
]
|
||||
|
||||
this.on('mount', () => {
|
||||
this.set();
|
||||
this.clock = setInterval(this.change, 20000);
|
||||
});
|
||||
|
||||
this.on('unmount', () => {
|
||||
clearInterval(this.clock);
|
||||
});
|
||||
|
||||
this.set = () => {
|
||||
this.$refs.text.innerHTML = this.tips[Math.floor(Math.random() * this.tips.length)];
|
||||
};
|
||||
|
||||
this.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>
|
||||
</mk-tips-home-widget>
|
@ -11,11 +11,11 @@ const isProduction = env === 'production';
|
||||
export default (version, lang) => {
|
||||
const plugins = [
|
||||
consts(lang),
|
||||
new StringReplacePlugin(),
|
||||
hoist()
|
||||
new StringReplacePlugin()
|
||||
];
|
||||
|
||||
if (isProduction) {
|
||||
plugins.push(hoist());
|
||||
plugins.push(minify());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user