forked from FoundKeyGang/FoundKey
* [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:
parent
763ae8f1a6
commit
8ca1fe3f0a
6 changed files with 209 additions and 44 deletions
174
src/client/app/common/views/components/drive-file-thumbnail.vue
Normal file
174
src/client/app/common/views/components/drive-file-thumbnail.vue
Normal 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>
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Reference in a new issue