diff --git a/src/web/app/common/define-widget.ts b/src/web/app/common/define-widget.ts index 782a69a62..4e83e37c6 100644 --- a/src/web/app/common/define-widget.ts +++ b/src/web/app/common/define-widget.ts @@ -26,7 +26,7 @@ export default function<T extends object>(data: { }, data() { return { - props: data.props || {} + props: data.props || {} as T }; }, watch: { diff --git a/src/web/app/common/views/components/index.ts b/src/web/app/common/views/components/index.ts index 740b73f9f..209a68fe5 100644 --- a/src/web/app/common/views/components/index.ts +++ b/src/web/app/common/views/components/index.ts @@ -13,6 +13,12 @@ import uploader from './uploader.vue'; import specialMessage from './special-message.vue'; import streamIndicator from './stream-indicator.vue'; import ellipsis from './ellipsis.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'; Vue.component('mk-signin', signin); Vue.component('mk-signup', signup); @@ -27,3 +33,9 @@ Vue.component('mk-uploader', uploader); Vue.component('mk-special-message', specialMessage); Vue.component('mk-stream-indicator', streamIndicator); Vue.component('mk-ellipsis', ellipsis); +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); diff --git a/src/web/app/common/views/components/widgets/photo-stream.vue b/src/web/app/common/views/components/widgets/photo-stream.vue index 12e568ca0..afbdc2162 100644 --- a/src/web/app/common/views/components/widgets/photo-stream.vue +++ b/src/web/app/common/views/components/widgets/photo-stream.vue @@ -44,7 +44,7 @@ export default define({ this.$root.$data.os.stream.dispose(this.connectionId); }, methods: { - onStreamDriveFileCreated(file) { + onDriveFileCreated(file) { if (/^image\/.+$/.test(file.type)) { this.images.unshift(file); if (this.images.length > 9) this.images.pop(); diff --git a/src/web/app/common/views/components/widgets/slideshow.vue b/src/web/app/common/views/components/widgets/slideshow.vue index 6dcd453e2..c24e3003c 100644 --- a/src/web/app/common/views/components/widgets/slideshow.vue +++ b/src/web/app/common/views/components/widgets/slideshow.vue @@ -102,7 +102,7 @@ export default define({ }); }, choose() { - this.wapi_selectDriveFolder().then(folder => { + this.$root.$data.api.chooseDriveFolder().then(folder => { this.props.folder = folder ? folder.id : null; this.fetch(); }); diff --git a/src/web/app/desktop/-tags/select-folder-from-drive-window.tag b/src/web/app/desktop/-tags/select-folder-from-drive-window.tag deleted file mode 100644 index 2f98f30a6..000000000 --- a/src/web/app/desktop/-tags/select-folder-from-drive-window.tag +++ /dev/null @@ -1,112 +0,0 @@ -<mk-select-folder-from-drive-window> - <mk-window ref="window" is-modal={ true } width={ '800px' } height={ '500px' }> - <yield to="header"> - <mk-raw content={ parent.title }/> - </yield> - <yield to="content"> - <mk-drive-browser ref="browser"/> - <div> - <button class="cancel" @click="parent.close">キャンセル</button> - <button class="ok" @click="parent.ok">決定</button> - </div> - </yield> - </mk-window> - <style lang="stylus" scoped> - :scope - > mk-window - [data-yield='header'] - > mk-raw - > [data-fa] - margin-right 4px - - [data-yield='content'] - > mk-drive-browser - height calc(100% - 72px) - - > div - height 72px - background lighten($theme-color, 95%) - - .ok - .cancel - display block - position absolute - bottom 16px - cursor pointer - padding 0 - margin 0 - width 120px - height 40px - font-size 1em - outline none - border-radius 4px - - &:focus - &:after - content "" - pointer-events none - position absolute - top -5px - right -5px - bottom -5px - left -5px - border 2px solid rgba($theme-color, 0.3) - border-radius 8px - - &:disabled - opacity 0.7 - cursor default - - .ok - right 16px - color $theme-color-foreground - background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%) - border solid 1px lighten($theme-color, 15%) - - &:not(:disabled) - font-weight bold - - &:hover:not(:disabled) - background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%) - border-color $theme-color - - &:active:not(:disabled) - background $theme-color - border-color $theme-color - - .cancel - right 148px - color #888 - background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%) - border solid 1px #e2e2e2 - - &:hover - background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%) - border-color #dcdcdc - - &:active - background #ececec - border-color #dcdcdc - - </style> - <script lang="typescript"> - this.files = []; - - this.title = this.opts.title || '%fa:R folder%フォルダを選択'; - - this.on('mount', () => { - this.$refs.window.on('closed', () => { - this.$destroy(); - }); - }); - - this.close = () => { - this.$refs.window.close(); - }; - - this.ok = () => { - this.$emit('selected', this.$refs.window.refs.browser.folder); - this.$refs.window.close(); - }; - </script> -</mk-select-folder-from-drive-window> diff --git a/src/web/app/desktop/api/choose-drive-folder.ts b/src/web/app/desktop/api/choose-drive-folder.ts new file mode 100644 index 000000000..a5116f7bc --- /dev/null +++ b/src/web/app/desktop/api/choose-drive-folder.ts @@ -0,0 +1,17 @@ +import MkChooseFolderFromDriveWindow from '../../../common/views/components/choose-folder-from-drive-window.vue'; + +export default function(this: any, opts) { + return new Promise((res, rej) => { + const o = opts || {}; + const w = new MkChooseFolderFromDriveWindow({ + parent: this, + propsData: { + title: o.title + } + }).$mount(); + w.$once('selected', folder => { + res(folder); + }); + document.body.appendChild(w.$el); + }); +} diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts index 1377965ea..cd894170e 100644 --- a/src/web/app/desktop/script.ts +++ b/src/web/app/desktop/script.ts @@ -10,6 +10,8 @@ import fuckAdBlock from './scripts/fuck-ad-block'; import HomeStreamManager from '../common/scripts/streaming/home-stream-manager'; import composeNotification from '../common/scripts/compose-notification'; +import chooseDriveFolder from './api/choose-drive-folder'; + import MkIndex from './views/pages/index.vue'; /** @@ -27,7 +29,9 @@ init(async (launch) => { // Register components require('./views/components'); - const app = launch(); + const app = launch({ + chooseDriveFolder + }); /** * Init Notification diff --git a/src/web/app/desktop/views/components/choose-file-from-drive-window.vue b/src/web/app/desktop/views/components/choose-file-from-drive-window.vue index ed9ca6466..5aa226f4c 100644 --- a/src/web/app/desktop/views/components/choose-file-from-drive-window.vue +++ b/src/web/app/desktop/views/components/choose-file-from-drive-window.vue @@ -14,7 +14,7 @@ /> <div :class="$style.footer"> <button :class="$style.upload" title="PCからドライブにファイルをアップロード" @click="upload">%fa:upload%</button> - <button :class="$style.cancel" @click="close">キャンセル</button> + <button :class="$style.cancel" @click="cancel">キャンセル</button> <button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">決定</button> </div> </mk-window> @@ -50,6 +50,9 @@ export default Vue.extend({ ok() { this.$emit('selected', this.multiple ? this.files : this.files[0]); (this.$refs.window as any).close(); + }, + cancel() { + (this.$refs.window as any).close(); } } }); diff --git a/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue b/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue new file mode 100644 index 000000000..0e598937e --- /dev/null +++ b/src/web/app/desktop/views/components/choose-folder-from-drive-window.vue @@ -0,0 +1,112 @@ +<template> +<mk-window ref="window" is-modal width='800px' height='500px' @closed="$destroy"> + <span slot="header"> + <span v-html="title" :class="$style.title"></span> + </span> + + <mk-drive + ref="browser" + :class="$style.browser" + :multiple="false" + /> + <div :class="$style.footer"> + <button :class="$style.cancel" @click="close">キャンセル</button> + <button :class="$style.ok" @click="ok">決定</button> + </div> +</mk-window> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + props: { + title: { + default: '%fa:R folder%フォルダを選択' + } + }, + methods: { + ok() { + this.$emit('selected', (this.$refs.browser as any).folder); + (this.$refs.window as any).close(); + }, + cancel() { + (this.$refs.window as any).close(); + } + } +}); +</script> + +<style lang="stylus" module> +.title + > [data-fa] + margin-right 4px + +.browser + height calc(100% - 72px) + +.footer + height 72px + background lighten($theme-color, 95%) + +.ok +.cancel + display block + position absolute + bottom 16px + cursor pointer + padding 0 + margin 0 + width 120px + height 40px + font-size 1em + outline none + border-radius 4px + + &:focus + &:after + content "" + pointer-events none + position absolute + top -5px + right -5px + bottom -5px + left -5px + border 2px solid rgba($theme-color, 0.3) + border-radius 8px + + &:disabled + opacity 0.7 + cursor default + +.ok + right 16px + color $theme-color-foreground + background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%) + border solid 1px lighten($theme-color, 15%) + + &:not(:disabled) + font-weight bold + + &:hover:not(:disabled) + background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%) + border-color $theme-color + + &:active:not(:disabled) + background $theme-color + border-color $theme-color + +.cancel + right 148px + color #888 + background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%) + border solid 1px #e2e2e2 + + &:hover + background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%) + border-color #dcdcdc + + &:active + background #ececec + border-color #dcdcdc + +</style> diff --git a/src/web/app/common/views/components/widgets/messaging.vue b/src/web/app/desktop/views/components/widgets/messaging.vue similarity index 100% rename from src/web/app/common/views/components/widgets/messaging.vue rename to src/web/app/desktop/views/components/widgets/messaging.vue diff --git a/src/web/app/init.ts b/src/web/app/init.ts index 0cea587a1..450327a58 100644 --- a/src/web/app/init.ts +++ b/src/web/app/init.ts @@ -22,7 +22,9 @@ require('./common/views/components'); Vue.mixin({ destroyed(this: any) { - this.$el.parentNode.removeChild(this.$el); + if (this.$el.parentNode) { + this.$el.parentNode.removeChild(this.$el); + } } }); @@ -74,18 +76,38 @@ if (localStorage.getItem('should-refresh') == 'true') { location.reload(true); } +type API = { + chooseDriveFile: (opts: { + title: string; + currentFolder: any; + multiple: boolean; + }) => Promise<any>; + + chooseDriveFolder: (opts: { + title: string; + currentFolder: any; + }) => Promise<any>; +}; + // MiOSを初期化してコールバックする -export default (callback: (launch: () => Vue) => void, sw = false) => { +export default (callback: (launch: (api: API) => Vue) => void, sw = false) => { const mios = new MiOS(sw); + Vue.mixin({ + data: { + $os: mios + } + }); + mios.init(() => { // アプリ基底要素マウント document.body.innerHTML = '<div id="app"></div>'; - const launch = () => { + const launch = (api: API) => { return new Vue({ data: { - os: mios + os: mios, + api: api }, router: new VueRouter({ mode: 'history'