summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-02-15 12:36:42 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-02-15 12:36:42 +0900
commitca604692628dcba95681964e8deec5ca75049c4e (patch)
tree0e26d2d049e83db42f9e9c9e275052f6a90ba55d
parentwip (diff)
downloadsharkey-ca604692628dcba95681964e8deec5ca75049c4e.tar.gz
sharkey-ca604692628dcba95681964e8deec5ca75049c4e.tar.bz2
sharkey-ca604692628dcba95681964e8deec5ca75049c4e.zip
wip
-rw-r--r--src/web/app/common/define-widget.ts4
-rw-r--r--src/web/app/common/views/components/widgets/calendar.vue192
-rw-r--r--src/web/app/common/views/components/widgets/donation.vue45
-rw-r--r--src/web/app/common/views/components/widgets/messaging.vue59
-rw-r--r--src/web/app/common/views/components/widgets/nav.vue29
-rw-r--r--src/web/app/common/views/components/widgets/photo-stream.vue122
-rw-r--r--src/web/app/common/views/components/widgets/profile.vue4
-rw-r--r--src/web/app/common/views/components/widgets/slideshow.vue154
-rw-r--r--src/web/app/common/views/components/widgets/tips.vue109
-rw-r--r--src/web/app/desktop/-tags/home-widgets/calendar.tag167
-rw-r--r--src/web/app/desktop/-tags/home-widgets/donation.tag36
-rw-r--r--src/web/app/desktop/-tags/home-widgets/messaging.tag52
-rw-r--r--src/web/app/desktop/-tags/home-widgets/nav.tag23
-rw-r--r--src/web/app/desktop/-tags/home-widgets/photo-stream.tag118
-rw-r--r--src/web/app/desktop/-tags/home-widgets/slideshow.tag151
-rw-r--r--src/web/app/desktop/-tags/home-widgets/tips.tag94
-rw-r--r--webpack/plugins/index.ts4
17 files changed, 716 insertions, 647 deletions
diff --git a/src/web/app/common/define-widget.ts b/src/web/app/common/define-widget.ts
index 5102ee1abf..782a69a624 100644
--- a/src/web/app/common/define-widget.ts
+++ b/src/web/app/common/define-widget.ts
@@ -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: {
diff --git a/src/web/app/common/views/components/widgets/calendar.vue b/src/web/app/common/views/components/widgets/calendar.vue
new file mode 100644
index 0000000000..308f43cd99
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/calendar.vue
@@ -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>
diff --git a/src/web/app/common/views/components/widgets/donation.vue b/src/web/app/common/views/components/widgets/donation.vue
new file mode 100644
index 0000000000..50adc531bf
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/donation.vue
@@ -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>
diff --git a/src/web/app/common/views/components/widgets/messaging.vue b/src/web/app/common/views/components/widgets/messaging.vue
new file mode 100644
index 0000000000..19ef704310
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/messaging.vue
@@ -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>
diff --git a/src/web/app/common/views/components/widgets/nav.vue b/src/web/app/common/views/components/widgets/nav.vue
new file mode 100644
index 0000000000..77e1eea492
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/nav.vue
@@ -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>
diff --git a/src/web/app/common/views/components/widgets/photo-stream.vue b/src/web/app/common/views/components/widgets/photo-stream.vue
new file mode 100644
index 0000000000..12e568ca00
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/photo-stream.vue
@@ -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>
diff --git a/src/web/app/common/views/components/widgets/profile.vue b/src/web/app/common/views/components/widgets/profile.vue
index e589eb20b9..70902c7cf5 100644
--- a/src/web/app/common/views/components/widgets/profile.vue
+++ b/src/web/app/common/views/components/widgets/profile.vue
@@ -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)' : '' }
diff --git a/src/web/app/common/views/components/widgets/slideshow.vue b/src/web/app/common/views/components/widgets/slideshow.vue
new file mode 100644
index 0000000000..6dcd453e25
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/slideshow.vue
@@ -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>
diff --git a/src/web/app/common/views/components/widgets/tips.vue b/src/web/app/common/views/components/widgets/tips.vue
new file mode 100644
index 0000000000..f38ecfe441
--- /dev/null
+++ b/src/web/app/common/views/components/widgets/tips.vue
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/calendar.tag b/src/web/app/desktop/-tags/home-widgets/calendar.tag
deleted file mode 100644
index 46d47662b9..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/calendar.tag
+++ /dev/null
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/donation.tag b/src/web/app/desktop/-tags/home-widgets/donation.tag
deleted file mode 100644
index 5ed5c137b5..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/donation.tag
+++ /dev/null
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/messaging.tag b/src/web/app/desktop/-tags/home-widgets/messaging.tag
deleted file mode 100644
index d3b77b58cc..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/messaging.tag
+++ /dev/null
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/nav.tag b/src/web/app/desktop/-tags/home-widgets/nav.tag
deleted file mode 100644
index 890fb4d8f7..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/nav.tag
+++ /dev/null
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/photo-stream.tag b/src/web/app/desktop/-tags/home-widgets/photo-stream.tag
deleted file mode 100644
index a2d95dede3..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/photo-stream.tag
+++ /dev/null
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/slideshow.tag b/src/web/app/desktop/-tags/home-widgets/slideshow.tag
deleted file mode 100644
index a69ab74b70..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/slideshow.tag
+++ /dev/null
@@ -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>
diff --git a/src/web/app/desktop/-tags/home-widgets/tips.tag b/src/web/app/desktop/-tags/home-widgets/tips.tag
deleted file mode 100644
index efe9c90fc2..0000000000
--- a/src/web/app/desktop/-tags/home-widgets/tips.tag
+++ /dev/null
@@ -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>
diff --git a/webpack/plugins/index.ts b/webpack/plugins/index.ts
index 9850db485c..d97f781558 100644
--- a/webpack/plugins/index.ts
+++ b/webpack/plugins/index.ts
@@ -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());
}