From 9fff26b9006c2d617f17c963eb62e36eb4b65271 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Sat, 23 Jan 2021 18:14:57 +0900 Subject: [PATCH] Implement drive setting page --- src/client/pages/settings/drive.vue | 200 ++++++++++++++++++++++++++-- src/client/pages/settings/index.vue | 6 +- 2 files changed, 195 insertions(+), 11 deletions(-) diff --git a/src/client/pages/settings/drive.vue b/src/client/pages/settings/drive.vue index 89c9b4bd69..8ca8bc9eec 100644 --- a/src/client/pages/settings/drive.vue +++ b/src/client/pages/settings/drive.vue @@ -1,33 +1,97 @@ <template> -<section class="uawsfosz _section"> - <div class="_title"><Fa :icon="faCloud"/> {{ $ts.drive }}</div> - <div class="_content"> - <span>{{ $ts.uploadFolder }}: {{ uploadFolder ? uploadFolder.name : '-' }}</span> - <MkButton primary @click="chooseUploadFolder()"><Fa :icon="faFolderOpen"/> {{ $ts.selectFolder }}</MkButton> +<FormBase class=""> + <FormGroup v-if="!fetching"> + <template #label>{{ $ts.usageAmount }}</template> + <div class="_formItem uawsfosz"> + <div class="_formPanel"> + <div class="meter"><div :style="meterStyle"></div></div> + </div> + </div> + <FormKeyValueView> + <template #key>{{ $ts.capacity }}</template> + <template #value>{{ bytes(capacity, 1) }}</template> + </FormKeyValueView> + <FormKeyValueView> + <template #key>{{ $ts.inUse }}</template> + <template #value>{{ bytes(usage, 1) }}</template> + </FormKeyValueView> + </FormGroup> + + <div class="_formItem"> + <div class="_formLabel">{{ $ts.statistics }}</div> + <div class="_formPanel"> + <div ref="chart"></div> + </div> </div> -</section> + + <FormButton :center="false" @click="chooseUploadFolder()" primary> + {{ $ts.uploadFolder }} + <template #suffix>{{ uploadFolder ? uploadFolder.name : '-' }}</template> + <template #suffixIcon><Fa :icon="faFolderOpen"/></template> + </FormButton> +</FormBase> </template> <script lang="ts"> import { defineComponent } from 'vue'; +import * as tinycolor from 'tinycolor2'; +import ApexCharts from 'apexcharts'; import { faCloud, faFolderOpen } from '@fortawesome/free-solid-svg-icons'; import { faClock, faEyeSlash, faTrashAlt } from '@fortawesome/free-regular-svg-icons'; -import MkButton from '@/components/ui/button.vue'; +import FormButton from '@/components/form/button.vue'; +import FormGroup from '@/components/form/group.vue'; +import FormKeyValueView from '@/components/form/key-value-view.vue'; +import FormBase from '@/components/form/base.vue'; import * as os from '@/os'; +import bytes from '@/filters/bytes'; export default defineComponent({ components: { - MkButton, + FormBase, + FormButton, + FormGroup, + FormKeyValueView, }, + emits: ['info'], + data() { return { + INFO: { + title: this.$ts.drive, + icon: faCloud + }, + fetching: true, + usage: null, + capacity: null, uploadFolder: null, faCloud, faClock, faEyeSlash, faFolderOpen, faTrashAlt } }, + computed: { + meterStyle(): any { + return { + width: `${this.usage / this.capacity * 100}%`, + background: tinycolor({ + h: 180 - (this.usage / this.capacity * 180), + s: 0.7, + l: 0.5 + }) + }; + } + }, + async created() { + os.api('drive').then(info => { + this.capacity = info.capacity; + this.usage = info.usage; + this.fetching = false; + this.$nextTick(() => { + this.renderChart(); + }); + }); + if (this.$store.state.uploadFolder) { this.uploadFolder = await os.api('drive/folders/show', { folderId: this.$store.state.uploadFolder @@ -35,6 +99,10 @@ export default defineComponent({ } }, + mounted() { + this.$emit('info', this.INFO); + }, + methods: { chooseUploadFolder() { os.selectDriveFolder(false).then(async folder => { @@ -48,13 +116,127 @@ export default defineComponent({ this.uploadFolder = null; } }); - } + }, + + renderChart() { + os.api('charts/user/drive', { + userId: this.$i.id, + span: 'day', + limit: 21 + }).then(stats => { + const addition = []; + const deletion = []; + const now = new Date(); + const y = now.getFullYear(); + const m = now.getMonth(); + const d = now.getDate(); + for (let i = 0; i < 21; i++) { + const x = new Date(y, m, d - i); + addition.push([ + x, + stats.incSize[i] + ]); + deletion.push([ + x, + -stats.decSize[i] + ]); + } + const chart = new ApexCharts(this.$refs.chart, { + chart: { + type: 'bar', + stacked: true, + height: 150, + toolbar: { + show: false + }, + zoom: { + enabled: false + } + }, + plotOptions: { + bar: { + columnWidth: '80%' + } + }, + grid: { + clipMarkers: false, + borderColor: 'rgba(0, 0, 0, 0.1)', + xaxis: { + lines: { + show: true, + } + }, + }, + tooltip: { + shared: true, + intersect: false, + theme: this.$store.state.darkMode ? 'dark' : 'light', + }, + dataLabels: { + enabled: false + }, + legend: { + show: false + }, + series: [{ + name: 'Additions', + data: addition + }, { + name: 'Deletions', + data: deletion + }], + xaxis: { + type: 'datetime', + labels: { + style: { + colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toRgbString() + } + }, + axisBorder: { + color: 'rgba(0, 0, 0, 0.1)' + }, + axisTicks: { + color: 'rgba(0, 0, 0, 0.1)' + }, + crosshairs: { + width: 1, + opacity: 1 + } + }, + yaxis: { + labels: { + formatter: v => bytes(v, 0), + style: { + colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toRgbString() + } + } + } + }); + chart.render(); + }); + }, + + bytes } }); </script> <style lang="scss" scoped> .uawsfosz { + > div { + padding: 24px; + > .meter { + $size: 12px; + background: rgba(0, 0, 0, 0.1); + border-radius: ($size / 2); + overflow: hidden; + + > div { + height: $size; + border-radius: ($size / 2); + } + } + } } </style> diff --git a/src/client/pages/settings/index.vue b/src/client/pages/settings/index.vue index bacce6e3f7..78aee4bfc1 100644 --- a/src/client/pages/settings/index.vue +++ b/src/client/pages/settings/index.vue @@ -6,6 +6,7 @@ <FormLink :active="page === 'profile'" replace to="/settings/profile"><template #icon><Fa :icon="faUser"/></template>{{ $ts.profile }}</FormLink> <FormLink :active="page === 'privacy'" replace to="/settings/privacy"><template #icon><Fa :icon="faLockOpen"/></template>{{ $ts.privacy }}</FormLink> <FormLink :active="page === 'reaction'" replace to="/settings/reaction"><template #icon><Fa :icon="faLaugh"/></template>{{ $ts.reaction }}</FormLink> + <FormLink :active="page === 'drive'" replace to="/settings/drive"><template #icon><Fa :icon="faCloud"/></template>{{ $ts.drive }}</FormLink> <FormLink :active="page === 'notifications'" replace to="/settings/notifications"><template #icon><Fa :icon="faBell"/></template>{{ $ts.notifications }}</FormLink> <FormLink :active="page === 'email'" replace to="/settings/email"><template #icon><Fa :icon="faEnvelope"/></template>{{ $ts.email }}</FormLink> <FormLink :active="page === 'integration'" replace to="/settings/integration"><template #icon><Fa :icon="faShareAlt"/></template>{{ $ts.integration }}</FormLink> @@ -42,7 +43,7 @@ <script lang="ts"> import { computed, defineAsyncComponent, defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue'; -import { faCog, faPalette, faPlug, faUser, faListUl, faLock, faCommentSlash, faMusic, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes } from '@fortawesome/free-solid-svg-icons'; +import { faCog, faPalette, faPlug, faUser, faListUl, faLock, faCommentSlash, faMusic, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faCloud } from '@fortawesome/free-solid-svg-icons'; import { faLaugh, faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons'; import { i18n } from '@/i18n'; import FormLink from '@/components/form/link.vue'; @@ -85,6 +86,7 @@ export default defineComponent({ case 'profile': return defineAsyncComponent(() => import('./profile.vue')); case 'privacy': return defineAsyncComponent(() => import('./privacy.vue')); case 'reaction': return defineAsyncComponent(() => import('./reaction.vue')); + case 'drive': return defineAsyncComponent(() => import('./drive.vue')); case 'notifications': return defineAsyncComponent(() => import('./notifications.vue')); case 'mute-block': return defineAsyncComponent(() => import('./mute-block.vue')); case 'word-mute': return defineAsyncComponent(() => import('./word-mute.vue')); @@ -157,7 +159,7 @@ export default defineComponent({ localStorage.removeItem('theme'); location.reload(); }, - faPalette, faPlug, faUser, faListUl, faLock, faLaugh, faCommentSlash, faMusic, faBell, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faEnvelope, + faPalette, faPlug, faUser, faListUl, faLock, faLaugh, faCommentSlash, faMusic, faBell, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faEnvelope, faCloud, }; }, });