summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-02-14 15:54:18 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-02-14 15:54:18 +0900
commit92e9f02e21f384fe7a81556bf3cf0468a404bb0a (patch)
tree0aedc03d347db1bbdeccb4add5ff9aff29e8d176 /src
parentwip (diff)
downloadmisskey-92e9f02e21f384fe7a81556bf3cf0468a404bb0a.tar.gz
misskey-92e9f02e21f384fe7a81556bf3cf0468a404bb0a.tar.bz2
misskey-92e9f02e21f384fe7a81556bf3cf0468a404bb0a.zip
wip
Diffstat (limited to 'src')
-rw-r--r--src/web/app/desktop/views/components/drive.vue (renamed from src/web/app/desktop/-tags/drive/browser.tag)824
1 files changed, 399 insertions, 425 deletions
diff --git a/src/web/app/desktop/-tags/drive/browser.tag b/src/web/app/desktop/views/components/drive.vue
index 7aaedab822..5d398dab98 100644
--- a/src/web/app/desktop/-tags/drive/browser.tag
+++ b/src/web/app/desktop/views/components/drive.vue
@@ -1,6 +1,7 @@
-<mk-drive-browser>
+<template>
+<div class="mk-drive">
<nav>
- <div class="path" oncontextmenu={ pathOncontextmenu }>
+ <div class="path" @contextmenu.prevent.stop="() => {}">
<mk-drive-browser-nav-folder :class="{ current: folder == null }" folder={ null }/>
<template each={ folder in hierarchyFolders }>
<span class="separator">%fa:angle-right%</span>
@@ -11,7 +12,15 @@
</div>
<input class="search" type="search" placeholder="&#xf002; %i18n:desktop.tags.mk-drive-browser.search%"/>
</nav>
- <div class="main { uploading: uploads.length > 0, fetching: fetching }" ref="main" onmousedown={ onmousedown } ondragover={ ondragover } ondragenter={ ondragenter } ondragleave={ ondragleave } ondrop={ ondrop } oncontextmenu={ oncontextmenu }>
+ <div class="main { uploading: uploads.length > 0, fetching: fetching }"
+ ref="main"
+ @mousedown="onMousedown"
+ @dragover.prevent.stop="onDragover"
+ @dragenter.prevent="onDragenter"
+ @dragleave="onDragleave"
+ @drop.prevent.stop="onDrop"
+ @contextmenu.prevent.stop="onContextmenu"
+ >
<div class="selection" ref="selection"></div>
<div class="contents" ref="contents">
<div class="folders" ref="foldersContainer" v-if="folders.length > 0">
@@ -44,323 +53,142 @@
</div>
</div>
<div class="dropzone" v-if="draghover"></div>
- <mk-uploader ref="uploader"/>
- <input ref="fileInput" type="file" accept="*/*" multiple="multiple" tabindex="-1" onchange={ changeFileInput }/>
- <style lang="stylus" scoped>
- :scope
- display block
+ <mk-uploader @change="onChangeUploaderUploads" @uploaded="onUploaderUploaded"/>
+ <input ref="fileInput" type="file" accept="*/*" multiple="multiple" tabindex="-1" @change="onChangeFileInput"/>
+</div>
+</template>
- > nav
- display block
- z-index 2
- width 100%
- overflow auto
- font-size 0.9em
- color #555
- background #fff
- //border-bottom 1px solid #dfdfdf
- box-shadow 0 1px 0 rgba(0, 0, 0, 0.05)
-
- &, *
- user-select none
-
- > .path
- display inline-block
- vertical-align bottom
- margin 0
- padding 0 8px
- width calc(100% - 200px)
- line-height 38px
- white-space nowrap
-
- > *
- display inline-block
- margin 0
- padding 0 8px
- line-height 38px
- cursor pointer
-
- i
- margin-right 4px
-
- *
- pointer-events none
-
- &:hover
- text-decoration underline
-
- &.current
- font-weight bold
- cursor default
-
- &:hover
- text-decoration none
-
- &.separator
- margin 0
- padding 0
- opacity 0.5
- cursor default
-
- > [data-fa]
- margin 0
-
- > .search
- display inline-block
- vertical-align bottom
- user-select text
- cursor auto
- margin 0
- padding 0 18px
- width 200px
- font-size 1em
- line-height 38px
- background transparent
- outline none
- //border solid 1px #ddd
- border none
- border-radius 0
- box-shadow none
- transition color 0.5s ease, border 0.5s ease
- font-family FontAwesome, sans-serif
-
- &[data-active='true']
- background #fff
-
- &::-webkit-input-placeholder,
- &:-ms-input-placeholder,
- &:-moz-placeholder
- color $ui-control-foreground-color
-
- > .main
- padding 8px
- height calc(100% - 38px)
- overflow auto
-
- &, *
- user-select none
-
- &.fetching
- cursor wait !important
-
- *
- pointer-events none
-
- > .contents
- opacity 0.5
-
- &.uploading
- height calc(100% - 38px - 100px)
-
- > .selection
- display none
- position absolute
- z-index 128
- top 0
- left 0
- border solid 1px $theme-color
- background rgba($theme-color, 0.5)
- pointer-events none
-
- > .contents
-
- > .folders
- > .files
- display flex
- flex-wrap wrap
-
- > .folder
- > .file
- flex-grow 1
- width 144px
- margin 4px
-
- > .padding
- flex-grow 1
- pointer-events none
- width 144px + 8px // 8px is margin
-
- > .empty
- padding 16px
- text-align center
- color #999
- pointer-events none
-
- > p
- margin 0
-
- > .fetching
- .spinner
- margin 100px auto
- width 40px
- height 40px
- text-align center
-
- animation sk-rotate 2.0s infinite linear
-
- .dot1, .dot2
- width 60%
- height 60%
- display inline-block
- position absolute
- top 0
- background-color rgba(0, 0, 0, 0.3)
- border-radius 100%
-
- animation sk-bounce 2.0s infinite ease-in-out
-
- .dot2
- top auto
- bottom 0
- animation-delay -1.0s
-
- @keyframes sk-rotate { 100% { transform: rotate(360deg); }}
-
- @keyframes sk-bounce {
- 0%, 100% {
- transform: scale(0.0);
- } 50% {
- transform: scale(1.0);
- }
- }
-
- > .dropzone
- position absolute
- left 0
- top 38px
- width 100%
- height calc(100% - 38px)
- border dashed 2px rgba($theme-color, 0.5)
- pointer-events none
-
- > mk-uploader
- height 100px
- padding 16px
- background #fff
-
- > input
- display none
+<script lang="ts">
+import Vue from 'vue';
+import contains from '../../../common/scripts/contains';
+import dialog from '../../scripts/dialog';
+import inputDialog from '../../scripts/input-dialog';
- </style>
- <script lang="typescript">
- import contains from '../../../common/scripts/contains';
- import dialog from '../../scripts/dialog';
- import inputDialog from '../../scripts/input-dialog';
+export default Vue.extend({
+ props: {
+ initFolder: {
+ required: false
+ },
+ multiple: {
+ default: false
+ }
+ },
+ data() {
+ return {
+ /**
+ * 現在の階層(フォルダ)
+ * * null でルートを表す
+ */
+ folder: null,
- this.mixin('i');
- this.mixin('api');
+ files: [],
+ folders: [],
+ moreFiles: false,
+ moreFolders: false,
+ hierarchyFolders: [],
+ selectedFiles: [],
+ uploadings: [],
+ connection: null,
+ connectionId: null,
- this.mixin('drive-stream');
- this.connection = this.driveStream.getConnection();
- this.connectionId = this.driveStream.use();
+ /**
+ * ドロップされようとしているか
+ */
+ draghover: false,
- this.files = [];
- this.folders = [];
- this.hierarchyFolders = [];
- this.selectedFiles = [];
+ /**
+ * 自信の所有するアイテムがドラッグをスタートさせたか
+ * (自分自身の階層にドロップできないようにするためのフラグ)
+ */
+ isDragSource: false,
- this.uploads = [];
-
- // 現在の階層(フォルダ)
- // * null でルートを表す
- this.folder = null;
-
- this.multiple = this.opts.multiple != null ? this.opts.multiple : false;
-
- // ドロップされようとしているか
- this.draghover = false;
-
- // 自信の所有するアイテムがドラッグをスタートさせたか
- // (自分自身の階層にドロップできないようにするためのフラグ)
- this.isDragSource = false;
-
- this.on('mount', () => {
- this.$refs.uploader.on('uploaded', file => {
- this.addFile(file, true);
- });
-
- this.$refs.uploader.on('change-uploads', uploads => {
- this.update({
- uploads: uploads
- });
- });
-
- this.connection.on('file_created', this.onStreamDriveFileCreated);
- this.connection.on('file_updated', this.onStreamDriveFileUpdated);
- this.connection.on('folder_created', this.onStreamDriveFolderCreated);
- this.connection.on('folder_updated', this.onStreamDriveFolderUpdated);
-
- if (this.opts.folder) {
- this.move(this.opts.folder);
- } else {
- this.fetch();
- }
- });
+ fetching: true
+ };
+ },
+ mounted() {
+ this.connection = this.$root.$data.os.streams.driveStream.getConnection();
+ this.connectionId = this.$root.$data.os.streams.driveStream.use();
- this.on('unmount', () => {
- this.connection.off('file_created', this.onStreamDriveFileCreated);
- this.connection.off('file_updated', this.onStreamDriveFileUpdated);
- this.connection.off('folder_created', this.onStreamDriveFolderCreated);
- this.connection.off('folder_updated', this.onStreamDriveFolderUpdated);
- this.driveStream.dispose(this.connectionId);
- });
+ this.connection.on('file_created', this.onStreamDriveFileCreated);
+ this.connection.on('file_updated', this.onStreamDriveFileUpdated);
+ this.connection.on('folder_created', this.onStreamDriveFolderCreated);
+ this.connection.on('folder_updated', this.onStreamDriveFolderUpdated);
- this.onStreamDriveFileCreated = file => {
+ if (this.initFolder) {
+ this.move(this.initFolder);
+ } else {
+ this.fetch();
+ }
+ },
+ beforeDestroy() {
+ this.connection.off('file_created', this.onStreamDriveFileCreated);
+ this.connection.off('file_updated', this.onStreamDriveFileUpdated);
+ this.connection.off('folder_created', this.onStreamDriveFolderCreated);
+ this.connection.off('folder_updated', this.onStreamDriveFolderUpdated);
+ this.$root.$data.os.streams.driveStream.dispose(this.connectionId);
+ },
+ methods: {
+ onStreamDriveFileCreated(file) {
this.addFile(file, true);
- };
-
- this.onStreamDriveFileUpdated = file => {
+ },
+ onStreamDriveFileUpdated(file) {
const current = this.folder ? this.folder.id : null;
if (current != file.folder_id) {
this.removeFile(file);
} else {
this.addFile(file, true);
}
- };
-
- this.onStreamDriveFolderCreated = folder => {
+ },
+ onStreamDriveFolderCreated(folder) {
this.addFolder(folder, true);
- };
-
- this.onStreamDriveFolderUpdated = folder => {
+ },
+ onStreamDriveFolderUpdated(folder) {
const current = this.folder ? this.folder.id : null;
if (current != folder.parent_id) {
this.removeFolder(folder);
} else {
this.addFolder(folder, true);
}
- };
-
- this.onmousedown = e => {
+ },
+ onChangeUploaderUploads(uploads) {
+ this.uploadings = uploads;
+ },
+ onUploaderUploaded(file) {
+ this.addFile(file, true);
+ },
+ onMousedown(e): any {
if (contains(this.$refs.foldersContainer, e.target) || contains(this.$refs.filesContainer, e.target)) return true;
- const rect = this.$refs.main.getBoundingClientRect();
+ const main = this.$refs.main as any;
+ const selection = this.$refs.selection as any;
- const left = e.pageX + this.$refs.main.scrollLeft - rect.left - window.pageXOffset
- const top = e.pageY + this.$refs.main.scrollTop - rect.top - window.pageYOffset
+ const rect = main.getBoundingClientRect();
+
+ const left = e.pageX + main.scrollLeft - rect.left - window.pageXOffset
+ const top = e.pageY + main.scrollTop - rect.top - window.pageYOffset
const move = e => {
- this.$refs.selection.style.display = 'block';
+ selection.style.display = 'block';
- const cursorX = e.pageX + this.$refs.main.scrollLeft - rect.left - window.pageXOffset;
- const cursorY = e.pageY + this.$refs.main.scrollTop - rect.top - window.pageYOffset;
+ const cursorX = e.pageX + main.scrollLeft - rect.left - window.pageXOffset;
+ const cursorY = e.pageY + main.scrollTop - rect.top - window.pageYOffset;
const w = cursorX - left;
const h = cursorY - top;
if (w > 0) {
- this.$refs.selection.style.width = w + 'px';
- this.$refs.selection.style.left = left + 'px';
+ selection.style.width = w + 'px';
+ selection.style.left = left + 'px';
} else {
- this.$refs.selection.style.width = -w + 'px';
- this.$refs.selection.style.left = cursorX + 'px';
+ selection.style.width = -w + 'px';
+ selection.style.left = cursorX + 'px';
}
if (h > 0) {
- this.$refs.selection.style.height = h + 'px';
- this.$refs.selection.style.top = top + 'px';
+ selection.style.height = h + 'px';
+ selection.style.top = top + 'px';
} else {
- this.$refs.selection.style.height = -h + 'px';
- this.$refs.selection.style.top = cursorY + 'px';
+ selection.style.height = -h + 'px';
+ selection.style.top = cursorY + 'px';
}
};
@@ -368,23 +196,13 @@
document.documentElement.removeEventListener('mousemove', move);
document.documentElement.removeEventListener('mouseup', up);
- this.$refs.selection.style.display = 'none';
+ selection.style.display = 'none';
};
document.documentElement.addEventListener('mousemove', move);
document.documentElement.addEventListener('mouseup', up);
- };
-
- this.pathOncontextmenu = e => {
- e.preventDefault();
- e.stopImmediatePropagation();
- return false;
- };
-
- this.ondragover = e => {
- e.preventDefault();
- e.stopPropagation();
-
+ },
+ onDragover(e): any {
// ドラッグ元が自分自身の所有するアイテムかどうか
if (!this.isDragSource) {
// ドラッグされてきたものがファイルだったら
@@ -395,21 +213,14 @@
e.dataTransfer.dropEffect = 'none';
return false;
}
- };
-
- this.ondragenter = e => {
- e.preventDefault();
+ },
+ onDragenter(e) {
if (!this.isDragSource) this.draghover = true;
- };
-
- this.ondragleave = e => {
+ },
+ onDragleave(e) {
this.draghover = false;
- };
-
- this.ondrop = e => {
- e.preventDefault();
- e.stopPropagation();
-
+ },
+ onDrop(e): any {
this.draghover = false;
// ドロップされてきたものがファイルだったら
@@ -433,7 +244,7 @@
const file = obj.id;
if (this.files.some(f => f.id == file)) return false;
this.removeFile(file);
- this.api('drive/files/update', {
+ this.$root.$data.os.api('drive/files/update', {
file_id: file,
folder_id: this.folder ? this.folder.id : null
});
@@ -444,7 +255,7 @@
if (this.folder && folder == this.folder.id) return false;
if (this.folders.some(f => f.id == folder)) return false;
this.removeFolder(folder);
- this.api('drive/folders/update', {
+ this.$root.$data.os.api('drive/folders/update', {
folder_id: folder,
parent_id: this.folder ? this.folder.id : null
}).then(() => {
@@ -464,32 +275,26 @@
}
return false;
- };
-
- this.oncontextmenu = e => {
- e.preventDefault();
- e.stopImmediatePropagation();
-
- const ctx = riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-base-contextmenu')), {
- browser: this
- })[0];
- ctx.open({
- x: e.pageX - window.pageXOffset,
- y: e.pageY - window.pageYOffset
- });
+ },
+ onContextmenu(e) {
+ document.body.appendChild(new MkDriveContextmenu({
+ propsData: {
+ browser: this,
+ x: e.pageX - window.pageXOffset,
+ y: e.pageY - window.pageYOffset
+ }
+ }).$mount().$el);
return false;
- };
-
- this.selectLocalFile = () => {
- this.$refs.fileInput.click();
- };
-
- this.urlUpload = () => {
+ },
+ selectLocalFile() {
+ (this.$refs.fileInput as any).click();
+ },
+ urlUpload() {
inputDialog('%i18n:desktop.tags.mk-drive-browser.url-upload%',
'%i18n:desktop.tags.mk-drive-browser.url-of-file%', null, url => {
- this.api('drive/files/upload_from_url', {
+ this.$root.$data.os.api('drive/files/upload_from_url', {
url: url,
folder_id: this.folder ? this.folder.id : undefined
});
@@ -499,34 +304,29 @@
text: '%i18n:common.ok%'
}]);
});
- };
-
- this.createFolder = () => {
+ },
+ createFolder() {
inputDialog('%i18n:desktop.tags.mk-drive-browser.create-folder%',
'%i18n:desktop.tags.mk-drive-browser.folder-name%', null, name => {
- this.api('drive/folders/create', {
+ this.$root.$data.os.api('drive/folders/create', {
name: name,
folder_id: this.folder ? this.folder.id : undefined
}).then(folder => {
this.addFolder(folder, true);
- this.update();
});
});
- };
-
- this.changeFileInput = () => {
- Array.from(this.$refs.fileInput.files).forEach(file => {
+ },
+ onChangeFileInput() {
+ Array.from((this.$refs.fileInput as any).files).forEach(file => {
this.upload(file, this.folder);
});
- };
-
- this.upload = (file, folder) => {
+ },
+ upload(file, folder) {
if (folder && typeof folder == 'object') folder = folder.id;
- this.$refs.uploader.upload(file, folder);
- };
-
- this.chooseFile = file => {
+ (this.$refs.uploader as any).upload(file, folder);
+ },
+ chooseFile(file) {
const isAlreadySelected = this.selectedFiles.some(f => f.id == file.id);
if (this.multiple) {
if (isAlreadySelected) {
@@ -534,7 +334,6 @@
} else {
this.selectedFiles.push(file);
}
- this.update();
this.$emit('change-selection', this.selectedFiles);
} else {
if (isAlreadySelected) {
@@ -544,15 +343,15 @@
this.$emit('change-selection', [file]);
}
}
- };
-
- this.newWindow = folderId => {
- riot.mount(document.body.appendChild(document.createElement('mk-drive-browser-window')), {
- folder: folderId
- });
- };
-
- this.move = target => {
+ },
+ newWindow(folderId) {
+ document.body.appendChild(new MkDriveWindow({
+ propsData: {
+ folder: folderId
+ }
+ }).$mount().$el);
+ },
+ move(target) {
if (target == null) {
this.goRoot();
return;
@@ -560,11 +359,9 @@
target = target.id;
}
- this.update({
- fetching: true
- });
+ this.fetching = true;
- this.api('drive/folders/show', {
+ this.$root.$data.os.api('drive/folders/show', {
folder_id: target
}).then(folder => {
this.folder = folder;
@@ -577,20 +374,17 @@
if (folder.parent) dive(folder.parent);
- this.update();
this.$emit('open-folder', folder);
this.fetch();
});
- };
-
- this.addFolder = (folder, unshift = false) => {
+ },
+ addFolder(folder, unshift = false) {
const current = this.folder ? this.folder.id : null;
if (current != folder.parent_id) return;
if (this.folders.some(f => f.id == folder.id)) {
const exist = this.folders.map(f => f.id).indexOf(folder.id);
- this.folders[exist] = folder;
- this.update();
+ this.folders[exist] = folder; // TODO
return;
}
@@ -599,18 +393,14 @@
} else {
this.folders.push(folder);
}
-
- this.update();
- };
-
- this.addFile = (file, unshift = false) => {
+ },
+ addFile(file, unshift = false) {
const current = this.folder ? this.folder.id : null;
if (current != file.folder_id) return;
if (this.files.some(f => f.id == file.id)) {
const exist = this.files.map(f => f.id).indexOf(file.id);
- this.files[exist] = file;
- this.update();
+ this.files[exist] = file; // TODO
return;
}
@@ -619,47 +409,42 @@
} else {
this.files.push(file);
}
-
- this.update();
- };
-
- this.removeFolder = folder => {
+ },
+ removeFolder(folder) {
if (typeof folder == 'object') folder = folder.id;
this.folders = this.folders.filter(f => f.id != folder);
- this.update();
- };
-
- this.removeFile = file => {
+ },
+ removeFile(file) {
if (typeof file == 'object') file = file.id;
this.files = this.files.filter(f => f.id != file);
- this.update();
- };
-
- this.appendFile = file => this.addFile(file);
- this.appendFolder = file => this.addFolder(file);
- this.prependFile = file => this.addFile(file, true);
- this.prependFolder = file => this.addFolder(file, true);
-
- this.goRoot = () => {
+ },
+ appendFile(file) {
+ this.addFile(file);
+ },
+ appendFolder(folder) {
+ this.addFolder(folder);
+ },
+ prependFile(file) {
+ this.addFile(file, true);
+ },
+ prependFolder(folder) {
+ this.addFolder(folder, true);
+ },
+ goRoot() {
// 既にrootにいるなら何もしない
if (this.folder == null) return;
- this.update({
- folder: null,
- hierarchyFolders: []
- });
+ this.folder = null;
+ this.hierarchyFolders = [];
this.$emit('move-root');
this.fetch();
- };
-
- this.fetch = () => {
- this.update({
- folders: [],
- files: [],
- moreFolders: false,
- moreFiles: false,
- fetching: true
- });
+ },
+ fetch() {
+ this.folders = [];
+ this.files = [];
+ this.moreFolders = false;
+ this.moreFiles = false;
+ this.fetching = true;
let fetchedFolders = null;
let fetchedFiles = null;
@@ -668,7 +453,7 @@
const filesMax = 30;
// フォルダ一覧取得
- this.api('drive/folders', {
+ this.$root.$data.os.api('drive/folders', {
folder_id: this.folder ? this.folder.id : null,
limit: foldersMax + 1
}).then(folders => {
@@ -681,7 +466,7 @@
});
// ファイル一覧取得
- this.api('drive/files', {
+ this.$root.$data.os.api('drive/files', {
folder_id: this.folder ? this.folder.id : null,
limit: filesMax + 1
}).then(files => {
@@ -698,24 +483,19 @@
if (flag) {
fetchedFolders.forEach(this.appendFolder);
fetchedFiles.forEach(this.appendFile);
- this.update({
- fetching: false
- });
+ this.fetching = false;
} else {
flag = true;
}
};
- };
-
- this.fetchMoreFiles = () => {
- this.update({
- fetching: true
- });
+ },
+ fetchMoreFiles() {
+ this.fetching = true;
const max = 30;
// ファイル一覧取得
- this.api('drive/files', {
+ this.$root.$data.os.api('drive/files', {
folder_id: this.folder ? this.folder.id : null,
limit: max + 1
}).then(files => {
@@ -726,11 +506,205 @@
this.moreFiles = false;
}
files.forEach(this.appendFile);
- this.update({
- fetching: false
- });
+ this.fetching = false;
});
- };
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-drive
+
+ > nav
+ display block
+ z-index 2
+ width 100%
+ overflow auto
+ font-size 0.9em
+ color #555
+ background #fff
+ //border-bottom 1px solid #dfdfdf
+ box-shadow 0 1px 0 rgba(0, 0, 0, 0.05)
+
+ &, *
+ user-select none
+
+ > .path
+ display inline-block
+ vertical-align bottom
+ margin 0
+ padding 0 8px
+ width calc(100% - 200px)
+ line-height 38px
+ white-space nowrap
+
+ > *
+ display inline-block
+ margin 0
+ padding 0 8px
+ line-height 38px
+ cursor pointer
+
+ i
+ margin-right 4px
+
+ *
+ pointer-events none
+
+ &:hover
+ text-decoration underline
+
+ &.current
+ font-weight bold
+ cursor default
+
+ &:hover
+ text-decoration none
+
+ &.separator
+ margin 0
+ padding 0
+ opacity 0.5
+ cursor default
+
+ > [data-fa]
+ margin 0
+
+ > .search
+ display inline-block
+ vertical-align bottom
+ user-select text
+ cursor auto
+ margin 0
+ padding 0 18px
+ width 200px
+ font-size 1em
+ line-height 38px
+ background transparent
+ outline none
+ //border solid 1px #ddd
+ border none
+ border-radius 0
+ box-shadow none
+ transition color 0.5s ease, border 0.5s ease
+ font-family FontAwesome, sans-serif
+
+ &[data-active='true']
+ background #fff
+
+ &::-webkit-input-placeholder,
+ &:-ms-input-placeholder,
+ &:-moz-placeholder
+ color $ui-control-foreground-color
+
+ > .main
+ padding 8px
+ height calc(100% - 38px)
+ overflow auto
+
+ &, *
+ user-select none
+
+ &.fetching
+ cursor wait !important
+
+ *
+ pointer-events none
+
+ > .contents
+ opacity 0.5
+
+ &.uploading
+ height calc(100% - 38px - 100px)
+
+ > .selection
+ display none
+ position absolute
+ z-index 128
+ top 0
+ left 0
+ border solid 1px $theme-color
+ background rgba($theme-color, 0.5)
+ pointer-events none
+
+ > .contents
+
+ > .folders
+ > .files
+ display flex
+ flex-wrap wrap
+
+ > .folder
+ > .file
+ flex-grow 1
+ width 144px
+ margin 4px
+
+ > .padding
+ flex-grow 1
+ pointer-events none
+ width 144px + 8px // 8px is margin
+
+ > .empty
+ padding 16px
+ text-align center
+ color #999
+ pointer-events none
+
+ > p
+ margin 0
+
+ > .fetching
+ .spinner
+ margin 100px auto
+ width 40px
+ height 40px
+ text-align center
+
+ animation sk-rotate 2.0s infinite linear
+
+ .dot1, .dot2
+ width 60%
+ height 60%
+ display inline-block
+ position absolute
+ top 0
+ background-color rgba(0, 0, 0, 0.3)
+ border-radius 100%
+
+ animation sk-bounce 2.0s infinite ease-in-out
+
+ .dot2
+ top auto
+ bottom 0
+ animation-delay -1.0s
+
+ @keyframes sk-rotate { 100% { transform: rotate(360deg); }}
+
+ @keyframes sk-bounce {
+ 0%, 100% {
+ transform: scale(0.0);
+ } 50% {
+ transform: scale(1.0);
+ }
+ }
+
+ > .dropzone
+ position absolute
+ left 0
+ top 38px
+ width 100%
+ height calc(100% - 38px)
+ border dashed 2px rgba($theme-color, 0.5)
+ pointer-events none
+
+ > .mk-uploader
+ height 100px
+ padding 16px
+ background #fff
+
+ > input
+ display none
- </script>
-</mk-drive-browser>
+</style>