* [client] show drive file icon

* 🎨

* exchange icon

* fix

* fuck crlf

* 背景差し戻し

* fix selected color

* 🎨

* fix

* pointer-events none

* fix bug

* ✌️

* Clean up

* ✌️

* Clean up

* Fix
This commit is contained in:
tamaina 2019-03-19 17:26:07 +09:00 committed by syuilo
parent bbc6027c09
commit 4d9c87626f
6 changed files with 209 additions and 44 deletions

View File

@ -0,0 +1,174 @@
<template>
<div class="zdjebgpv" :class="{ detail }" ref="thumbnail" :style="`background-color: ${ background }`">
<img
:src="file.url"
:alt="file.name"
:title="file.name"
v-if="detail && is === 'image'"/>
<video
:src="file.url"
ref="volumectrl"
preload="metadata"
controls
v-else-if="detail && is === 'video'"/>
<img :src="file.thumbnailUrl" alt="" @load="onThumbnailLoaded" :style="`object-fit: ${ fit }`" v-else-if="isThumbnailAvailable"/>
<fa :icon="faFileImage" class="icon" v-else-if="is === 'image'"/>
<fa :icon="faFileVideo" class="icon" v-else-if="is === 'video'"/>
<audio
:src="file.url"
ref="volumectrl"
preload="metadata"
controls
v-else-if="detail && is === 'audio'"/>
<fa :icon="faMusic" class="icon" v-else-if="is === 'audio' || is === 'midi'"/>
<fa :icon="faFileCsv" class="icon" v-else-if="is === 'csv'"/>
<fa :icon="faFilePdf" class="icon" v-else-if="is === 'pdf'"/>
<fa :icon="faFileAlt" class="icon" v-else-if="is === 'textfile'"/>
<fa :icon="faFileArchive" class="icon" v-else-if="is === 'archive'"/>
<fa :icon="faFile" class="icon" v-else/>
<fa :icon="faFilm" class="icon-sub" v-if="!detail && isThumbnailAvailable && is === 'video'"/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import anime from 'animejs';
import i18n from '../../../i18n';
import {
faFile,
faFileAlt,
faFileImage,
faMusic,
faFileVideo,
faFileCsv,
faFilePdf,
faFileArchive,
faFilm
} from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
props: {
file: {
type: Object,
required: true
},
fit: {
type: String,
required: true
},
detail: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
isContextmenuShowing: false,
isDragging: false,
faFile,
faFileAlt,
faFileImage,
faMusic,
faFileVideo,
faFileCsv,
faFilePdf,
faFileArchive,
faFilm
};
},
computed: {
is(): 'image' | 'video' | 'midi' | 'audio' | 'csv' | 'pdf' | 'textfile' | 'archive' | 'unknown' {
if (this.file.type.startsWith('image/')) return 'image';
if (this.file.type.startsWith('video/')) return 'video';
if (this.file.type === 'audio/midi') return 'midi';
if (this.file.type.startsWith('audio/')) return 'audio';
if (this.file.type.endsWith('/csv')) return 'csv';
if (this.file.type.endsWith('/pdf')) return 'pdf';
if (this.file.type.startsWith('text/')) return 'textfile';
if ([
"application/zip",
"application/x-cpio",
"application/x-bzip",
"application/x-bzip2",
"application/java-archive",
"application/x-rar-compressed",
"application/x-tar",
"application/gzip",
"application/x-7z-compressed"
].some(e => e === this.file.type)) return 'archive';
return 'unknown';
},
isThumbnailAvailable(): boolean {
return this.file.thumbnailUrl.endsWith('?thumbnail') ? (this.is === 'image' || this.is === 'video') : true;
},
background(): string {
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3
? `rgb(${this.file.properties.avgColor.join(',')})`
: 'transparent';
}
},
mounted() {
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume;
},
methods: {
onThumbnailLoaded() {
if (this.file.properties.avgColor && this.file.properties.avgColor.length == 3) {
anime({
targets: this.$refs.thumbnail,
backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`,
duration: 100,
easing: 'linear'
});
}
},
volumechange() {
const audioTag = this.$refs.volumectrl as HTMLAudioElement;
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
}
}
});
</script>
<style lang="stylus" scoped>
.zdjebgpv
display flex
> img,
> .icon
pointer-events none
> img
height 100%
width 100%
margin auto
object-fit cover
> .icon
height 65%
width 65%
margin auto
> video,
> audio
width 100%
> .icon-sub
position absolute
width 30%
height auto
margin 0
right 4%
bottom 4%
&.detail
> .icon
height 100px
margin 16px auto
</style>

View File

@ -21,9 +21,9 @@
<img src="/assets/label-red.svg"/> <img src="/assets/label-red.svg"/>
<p>{{ $t('nsfw') }}</p> <p>{{ $t('nsfw') }}</p>
</div> </div>
<div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`">
<img :src="file.thumbnailUrl" alt="" @load="onThumbnailLoaded"/> <x-file-thumbnail class="thumbnail" :file="file" fit="contain"/>
</div>
<p class="name"> <p class="name">
<span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span> <span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span>
<span class="ext" v-if="file.name.lastIndexOf('.') != -1">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span> <span class="ext" v-if="file.name.lastIndexOf('.') != -1">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span>
@ -34,15 +34,18 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import anime from 'animejs';
import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
import updateAvatar from '../../api/update-avatar'; import updateAvatar from '../../api/update-avatar';
import updateBanner from '../../api/update-banner'; import updateBanner from '../../api/update-banner';
import { appendQuery } from '../../../../../prelude/url'; import { appendQuery } from '../../../../../prelude/url';
import XFileThumbnail from '../../../common/views/components/drive-file-thumbnail.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('desktop/views/components/drive.file.vue'), i18n: i18n('desktop/views/components/drive.file.vue'),
props: ['file'], props: ['file'],
components: {
XFileThumbnail
},
data() { data() {
return { return {
isContextmenuShowing: false, isContextmenuShowing: false,
@ -58,11 +61,6 @@ export default Vue.extend({
}, },
title(): string { title(): string {
return `${this.file.name}\n${this.file.type} ${Vue.filter('bytes')(this.file.datasize)}`; return `${this.file.name}\n${this.file.type} ${Vue.filter('bytes')(this.file.datasize)}`;
},
background(): string {
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3
? `rgb(${this.file.properties.avgColor.join(',')})`
: 'transparent';
} }
}, },
methods: { methods: {
@ -256,6 +254,9 @@ export default Vue.extend({
> .name > .name
color var(--primaryForeground) color var(--primaryForeground)
> .thumbnail
color var(--primaryForeground)
&[data-is-contextmenu-showing] &[data-is-contextmenu-showing]
&:after &:after
content "" content ""
@ -321,18 +322,7 @@ export default Vue.extend({
width 128px width 128px
height 128px height 128px
margin auto margin auto
color var(--driveFileIcon)
> img
display block
position absolute
top 0
left 0
right 0
bottom 0
margin auto
max-width 128px
max-height 128px
pointer-events none
> .name > .name
display block display block

View File

@ -1,11 +1,7 @@
<template> <template>
<div class="pyvicwrksnfyhpfgkjwqknuururpaztw"> <div class="pyvicwrksnfyhpfgkjwqknuururpaztw">
<div class="preview"> <div class="preview">
<img v-if="kind == 'image'" ref="img" <x-file-thumbnail class="preview" :file="file" fit="cover" :detail="true"/>
:src="file.url"
:alt="file.name"
:title="file.name"
:style="style">
<template v-if="kind != 'image'"><fa icon="file"/></template> <template v-if="kind != 'image'"><fa icon="file"/></template>
<footer v-if="kind == 'image' && file.properties && file.properties.width && file.properties.height"> <footer v-if="kind == 'image' && file.properties && file.properties.width && file.properties.height">
<span class="size"> <span class="size">
@ -62,11 +58,16 @@ import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import { gcd } from '../../../../../prelude/math'; import { gcd } from '../../../../../prelude/math';
import { appendQuery } from '../../../../../prelude/url'; import { appendQuery } from '../../../../../prelude/url';
import XFileThumbnail from '../../../common/views/components/drive-file-thumbnail.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('mobile/views/components/drive.file-detail.vue'), i18n: i18n('mobile/views/components/drive.file-detail.vue'),
props: ['file'], props: ['file'],
components: {
XFileThumbnail
},
data() { data() {
return { return {
gcd, gcd,
@ -147,8 +148,7 @@ export default Vue.extend({
padding 8px padding 8px
background var(--bg) background var(--bg)
> img > .preview
display block
max-width 100% max-width 100%
max-height 300px max-height 300px
margin 0 auto margin 0 auto

View File

@ -1,7 +1,7 @@
<template> <template>
<a class="vupkuhvjnjyqaqhsiogfbywvjxynrgsm" @click.prevent="onClick" :href="`/i/drive/file/${ file.id }`" :data-is-selected="isSelected"> <a class="vupkuhvjnjyqaqhsiogfbywvjxynrgsm" @click.prevent="onClick" :href="`/i/drive/file/${ file.id }`" :data-is-selected="isSelected">
<div class="container"> <div class="container">
<div class="thumbnail" :style="thumbnail"></div> <x-file-thumbnail class="thumbnail" :file="file" fit="cover"/>
<div class="body"> <div class="body">
<p class="name"> <p class="name">
<span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span> <span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span>
@ -26,9 +26,14 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import XFileThumbnail from '../../../common/views/components/drive-file-thumbnail.vue';
export default Vue.extend({ export default Vue.extend({
i18n: i18n('mobile/views/components/drive.file.vue'), i18n: i18n('mobile/views/components/drive.file.vue'),
props: ['file'], props: ['file'],
components: {
XFileThumbnail
},
data() { data() {
return { return {
isSelected: false isSelected: false
@ -37,12 +42,6 @@ export default Vue.extend({
computed: { computed: {
browser(): any { browser(): any {
return this.$parent; return this.$parent;
},
thumbnail(): any {
return {
'background-color': this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? `rgb(${this.file.properties.avgColor.join(',')})` : 'transparent',
'background-image': `url(${this.file.thumbnailUrl})`
};
} }
}, },
created() { created() {
@ -74,9 +73,12 @@ export default Vue.extend({
pointer-events none pointer-events none
> .container > .container
display grid
max-width 500px max-width 500px
margin 0 auto margin 0 auto
padding 16px padding 16px
grid-template-columns 64px 1fr
grid-column-gap 10px
&:after &:after
content "" content ""
@ -84,18 +86,13 @@ export default Vue.extend({
clear both clear both
> .thumbnail > .thumbnail
display block
float left
width 64px width 64px
height 64px height 64px
background-size cover color var(--driveFileIcon)
background-position center center
> .body > .body
display block display block
float left word-break break-all
width calc(100% - 74px)
margin-left 10px
> .name > .name
display block display block
@ -154,6 +151,6 @@ export default Vue.extend({
background var(--primary) background var(--primary)
&, * &, *
color #fff !important color var(--primaryForeground) !important
</style> </style>

View File

@ -153,6 +153,8 @@
messagingRoomMessageBg: '$secondary', messagingRoomMessageBg: '$secondary',
messagingRoomMessageFg: '#fff', messagingRoomMessageFg: '#fff',
driveFileIcon: '$text',
formButtonBorder: 'rgba(255, 255, 255, 0.1)', formButtonBorder: 'rgba(255, 255, 255, 0.1)',
formButtonHoverBg: ':alpha<0.2<$primary', formButtonHoverBg: ':alpha<0.2<$primary',
formButtonHoverBorder: ':alpha<0.5<$primary', formButtonHoverBorder: ':alpha<0.5<$primary',

View File

@ -153,6 +153,8 @@
messagingRoomMessageBg: '#eee', messagingRoomMessageBg: '#eee',
messagingRoomMessageFg: '#333', messagingRoomMessageFg: '#333',
driveFileIcon: '$text',
formButtonBorder: 'rgba(0, 0, 0, 0.1)', formButtonBorder: 'rgba(0, 0, 0, 0.1)',
formButtonHoverBg: ':alpha<0.12<$primary', formButtonHoverBg: ':alpha<0.12<$primary',
formButtonHoverBorder: ':alpha<0.3<$primary', formButtonHoverBorder: ':alpha<0.3<$primary',
@ -179,7 +181,7 @@
desktopTimelineSrcHover: ':darken<7<$text', desktopTimelineSrcHover: ':darken<7<$text',
desktopWindowTitle: '$text', desktopWindowTitle: '$text',
desktopWindowShadow: 'rgba(0, 0, 0, 0.2)', desktopWindowShadow: 'rgba(0, 0, 0, 0.2)',
desktopDriveBg: '#fff', desktopDriveBg: '@bg',
desktopDriveFolderBg: ':lighten<31<$primary', desktopDriveFolderBg: ':lighten<31<$primary',
desktopDriveFolderHoverBg: ':lighten<27<$primary', desktopDriveFolderHoverBg: ':lighten<27<$primary',
desktopDriveFolderActiveBg: ':lighten<25<$primary', desktopDriveFolderActiveBg: ':lighten<25<$primary',