mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-21 17:37:29 -07:00
* [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
bbc6027c09
commit
4d9c87626f
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"/>
|
||||
<p>{{ $t('nsfw') }}</p>
|
||||
</div>
|
||||
<div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`">
|
||||
<img :src="file.thumbnailUrl" alt="" @load="onThumbnailLoaded"/>
|
||||
</div>
|
||||
|
||||
<x-file-thumbnail class="thumbnail" :file="file" fit="contain"/>
|
||||
|
||||
<p class="name">
|
||||
<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>
|
||||
|
@ -34,15 +34,18 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import anime from 'animejs';
|
||||
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
|
||||
import updateAvatar from '../../api/update-avatar';
|
||||
import updateBanner from '../../api/update-banner';
|
||||
import { appendQuery } from '../../../../../prelude/url';
|
||||
import XFileThumbnail from '../../../common/views/components/drive-file-thumbnail.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('desktop/views/components/drive.file.vue'),
|
||||
props: ['file'],
|
||||
components: {
|
||||
XFileThumbnail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isContextmenuShowing: false,
|
||||
|
@ -58,11 +61,6 @@ export default Vue.extend({
|
|||
},
|
||||
title(): string {
|
||||
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: {
|
||||
|
@ -256,6 +254,9 @@ export default Vue.extend({
|
|||
> .name
|
||||
color var(--primaryForeground)
|
||||
|
||||
> .thumbnail
|
||||
color var(--primaryForeground)
|
||||
|
||||
&[data-is-contextmenu-showing]
|
||||
&:after
|
||||
content ""
|
||||
|
@ -321,18 +322,7 @@ export default Vue.extend({
|
|||
width 128px
|
||||
height 128px
|
||||
margin auto
|
||||
|
||||
> img
|
||||
display block
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
right 0
|
||||
bottom 0
|
||||
margin auto
|
||||
max-width 128px
|
||||
max-height 128px
|
||||
pointer-events none
|
||||
color var(--driveFileIcon)
|
||||
|
||||
> .name
|
||||
display block
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
<template>
|
||||
<div class="pyvicwrksnfyhpfgkjwqknuururpaztw">
|
||||
<div class="preview">
|
||||
<img v-if="kind == 'image'" ref="img"
|
||||
:src="file.url"
|
||||
:alt="file.name"
|
||||
:title="file.name"
|
||||
:style="style">
|
||||
<x-file-thumbnail class="preview" :file="file" fit="cover" :detail="true"/>
|
||||
<template v-if="kind != 'image'"><fa icon="file"/></template>
|
||||
<footer v-if="kind == 'image' && file.properties && file.properties.width && file.properties.height">
|
||||
<span class="size">
|
||||
|
@ -62,11 +58,16 @@ import Vue from 'vue';
|
|||
import i18n from '../../../i18n';
|
||||
import { gcd } from '../../../../../prelude/math';
|
||||
import { appendQuery } from '../../../../../prelude/url';
|
||||
import XFileThumbnail from '../../../common/views/components/drive-file-thumbnail.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('mobile/views/components/drive.file-detail.vue'),
|
||||
props: ['file'],
|
||||
|
||||
components: {
|
||||
XFileThumbnail
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
gcd,
|
||||
|
@ -147,8 +148,7 @@ export default Vue.extend({
|
|||
padding 8px
|
||||
background var(--bg)
|
||||
|
||||
> img
|
||||
display block
|
||||
> .preview
|
||||
max-width 100%
|
||||
max-height 300px
|
||||
margin 0 auto
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<a class="vupkuhvjnjyqaqhsiogfbywvjxynrgsm" @click.prevent="onClick" :href="`/i/drive/file/${ file.id }`" :data-is-selected="isSelected">
|
||||
<div class="container">
|
||||
<div class="thumbnail" :style="thumbnail"></div>
|
||||
<x-file-thumbnail class="thumbnail" :file="file" fit="cover"/>
|
||||
<div class="body">
|
||||
<p class="name">
|
||||
<span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span>
|
||||
|
@ -26,9 +26,14 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import XFileThumbnail from '../../../common/views/components/drive-file-thumbnail.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('mobile/views/components/drive.file.vue'),
|
||||
props: ['file'],
|
||||
components: {
|
||||
XFileThumbnail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSelected: false
|
||||
|
@ -37,12 +42,6 @@ export default Vue.extend({
|
|||
computed: {
|
||||
browser(): any {
|
||||
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() {
|
||||
|
@ -74,9 +73,12 @@ export default Vue.extend({
|
|||
pointer-events none
|
||||
|
||||
> .container
|
||||
display grid
|
||||
max-width 500px
|
||||
margin 0 auto
|
||||
padding 16px
|
||||
grid-template-columns 64px 1fr
|
||||
grid-column-gap 10px
|
||||
|
||||
&:after
|
||||
content ""
|
||||
|
@ -84,18 +86,13 @@ export default Vue.extend({
|
|||
clear both
|
||||
|
||||
> .thumbnail
|
||||
display block
|
||||
float left
|
||||
width 64px
|
||||
height 64px
|
||||
background-size cover
|
||||
background-position center center
|
||||
color var(--driveFileIcon)
|
||||
|
||||
> .body
|
||||
display block
|
||||
float left
|
||||
width calc(100% - 74px)
|
||||
margin-left 10px
|
||||
word-break break-all
|
||||
|
||||
> .name
|
||||
display block
|
||||
|
@ -154,6 +151,6 @@ export default Vue.extend({
|
|||
background var(--primary)
|
||||
|
||||
&, *
|
||||
color #fff !important
|
||||
color var(--primaryForeground) !important
|
||||
|
||||
</style>
|
||||
|
|
|
@ -153,6 +153,8 @@
|
|||
messagingRoomMessageBg: '$secondary',
|
||||
messagingRoomMessageFg: '#fff',
|
||||
|
||||
driveFileIcon: '$text',
|
||||
|
||||
formButtonBorder: 'rgba(255, 255, 255, 0.1)',
|
||||
formButtonHoverBg: ':alpha<0.2<$primary',
|
||||
formButtonHoverBorder: ':alpha<0.5<$primary',
|
||||
|
|
|
@ -153,6 +153,8 @@
|
|||
messagingRoomMessageBg: '#eee',
|
||||
messagingRoomMessageFg: '#333',
|
||||
|
||||
driveFileIcon: '$text',
|
||||
|
||||
formButtonBorder: 'rgba(0, 0, 0, 0.1)',
|
||||
formButtonHoverBg: ':alpha<0.12<$primary',
|
||||
formButtonHoverBorder: ':alpha<0.3<$primary',
|
||||
|
@ -179,7 +181,7 @@
|
|||
desktopTimelineSrcHover: ':darken<7<$text',
|
||||
desktopWindowTitle: '$text',
|
||||
desktopWindowShadow: 'rgba(0, 0, 0, 0.2)',
|
||||
desktopDriveBg: '#fff',
|
||||
desktopDriveBg: '@bg',
|
||||
desktopDriveFolderBg: ':lighten<31<$primary',
|
||||
desktopDriveFolderHoverBg: ':lighten<27<$primary',
|
||||
desktopDriveFolderActiveBg: ':lighten<25<$primary',
|
||||
|
|
Loading…
Reference in a new issue