diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2018-09-04 02:09:56 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2018-09-04 02:09:56 +0900 |
| commit | 3698c679e23c184e897d86e9d75dfe2a110a282c (patch) | |
| tree | f17584778c11ecd4055d350f99eb4be76b6a1f15 /src/client/app/common/views/components | |
| parent | 8.23.0 (diff) | |
| download | misskey-3698c679e23c184e897d86e9d75dfe2a110a282c.tar.gz misskey-3698c679e23c184e897d86e9d75dfe2a110a282c.tar.bz2 misskey-3698c679e23c184e897d86e9d75dfe2a110a282c.zip | |
:pizza:
Diffstat (limited to 'src/client/app/common/views/components')
| -rw-r--r-- | src/client/app/common/views/components/index.ts | 2 | ||||
| -rw-r--r-- | src/client/app/common/views/components/trends.chart.vue | 89 | ||||
| -rw-r--r-- | src/client/app/common/views/components/trends.vue | 105 |
3 files changed, 196 insertions, 0 deletions
diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 422a3da050..4700b6269e 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -1,5 +1,6 @@ import Vue from 'vue'; +import trends from './trends.vue'; import analogClock from './analog-clock.vue'; import menu from './menu.vue'; import noteHeader from './note-header.vue'; @@ -40,6 +41,7 @@ import uiSelect from './ui/select.vue'; import formButton from './ui/form/button.vue'; import formRadio from './ui/form/radio.vue'; +Vue.component('mk-trends', trends); Vue.component('mk-analog-clock', analogClock); Vue.component('mk-menu', menu); Vue.component('mk-note-header', noteHeader); diff --git a/src/client/app/common/views/components/trends.chart.vue b/src/client/app/common/views/components/trends.chart.vue new file mode 100644 index 0000000000..723a3947f8 --- /dev/null +++ b/src/client/app/common/views/components/trends.chart.vue @@ -0,0 +1,89 @@ +<template> +<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" style="overflow:visible"> + <defs> + <linearGradient :id="gradientId" x1="0" x2="0" y1="1" y2="0"> + <stop offset="0%" stop-color="hsl(200, 80%, 70%)"></stop> + <stop offset="100%" stop-color="hsl(90, 80%, 70%)"></stop> + </linearGradient> + <mask :id="maskId" x="0" y="0" :width="viewBoxX" :height="viewBoxY"> + <polygon + :points="polygonPoints" + fill="#fff" + fill-opacity="0.5"/> + <polyline + :points="polylinePoints" + fill="none" + stroke="#fff" + stroke-width="2"/> + <circle + :cx="headX" + :cy="headY" + r="3" + fill="#fff"/> + </mask> + </defs> + <rect + x="-10" y="-10" + :width="viewBoxX + 20" :height="viewBoxY + 20" + :style="`stroke: none; fill: url(#${ gradientId }); mask: url(#${ maskId })`"/> +</svg> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import * as uuid from 'uuid'; + +export default Vue.extend({ + props: { + src: { + type: Array, + required: true + } + }, + data() { + return { + viewBoxX: 50, + viewBoxY: 30, + gradientId: uuid(), + maskId: uuid(), + polylinePoints: '', + polygonPoints: '', + headX: null, + headY: null, + clock: null + }; + }, + watch: { + src() { + this.draw(); + } + }, + created() { + this.draw(); + + // Vueが何故かWatchを発動させない場合があるので + this.clock = setInterval(this.draw, 1000); + }, + beforeDestroy() { + clearInterval(this.clock); + }, + methods: { + draw() { + const stats = this.src.slice().reverse(); + const peak = Math.max.apply(null, stats) || 1; + + const polylinePoints = stats.map((n, i) => [ + i * (this.viewBoxX / (stats.length - 1)), + (1 - (n / peak)) * this.viewBoxY + ]); + + this.polylinePoints = polylinePoints.map(xy => `${xy[0]},${xy[1]}`).join(' '); + + this.polygonPoints = `0,${ this.viewBoxY } ${ this.polylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`; + + this.headX = polylinePoints[polylinePoints.length - 1][0]; + this.headY = polylinePoints[polylinePoints.length - 1][1]; + } + } +}); +</script> diff --git a/src/client/app/common/views/components/trends.vue b/src/client/app/common/views/components/trends.vue new file mode 100644 index 0000000000..627edc3876 --- /dev/null +++ b/src/client/app/common/views/components/trends.vue @@ -0,0 +1,105 @@ +<template> +<div class="csqvmxybqbycalfhkxvyfrgbrdalkaoc"> + <p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> + <p class="empty" v-else-if="stats.length == 0">%fa:exclamation-circle%%i18n:@empty%</p> + <!-- トランジションを有効にするとなぜかメモリリークする --> + <!-- <transition-group v-else tag="div" name="chart"> --> + <div> + <div v-for="stat in stats" :key="stat.tag"> + <div class="tag"> + <router-link :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link> + <p>{{ '%i18n:@count%'.replace('{}', stat.usersCount) }}</p> + </div> + <x-chart class="chart" :src="stat.chart"/> + </div> + </div> + <!-- </transition-group> --> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import XChart from './trends.chart.vue'; + +export default Vue.extend({ + components: { + XChart + }, + data() { + return { + stats: [], + fetching: true, + clock: null + }; + }, + mounted() { + this.fetch(); + this.clock = setInterval(this.fetch, 1000 * 60); + }, + beforeDestroy() { + clearInterval(this.clock); + }, + methods: { + fetch() { + (this as any).api('hashtags/trend').then(stats => { + this.stats = stats; + this.fetching = false; + }); + } + } +}); +</script> + +<style lang="stylus" scoped> +root(isDark) + > .fetching + > .empty + margin 0 + padding 16px + text-align center + color #aaa + + > [data-fa] + margin-right 4px + + > div + .chart-move + transition transform 1s ease + + > div + display flex + align-items center + padding 14px 16px + + &:not(:last-child) + border-bottom solid 1px isDark ? #393f4f : #eee + + > .tag + flex 1 + overflow hidden + font-size 14px + color isDark ? #9baec8 : #65727b + + > a + display block + width 100% + white-space nowrap + overflow hidden + text-overflow ellipsis + color inherit + + > p + margin 0 + font-size 75% + opacity 0.7 + + > .chart + height 30px + +.csqvmxybqbycalfhkxvyfrgbrdalkaoc[data-darkmode] + root(true) + +.csqvmxybqbycalfhkxvyfrgbrdalkaoc:not([data-darkmode]) + root(false) + +</style> |