Refactor video card component

This commit is contained in:
the1812 2019-09-12 10:49:17 +08:00
parent 987eed51b4
commit 6eb20d37d5
14 changed files with 342 additions and 278 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -66,7 +66,7 @@
"hide-category.min.js": "64125DCFE1F7DB269049CB839B52E38B4E2D574E7A1AF6A5439BF0B77EB93EC1", "hide-category.min.js": "64125DCFE1F7DB269049CB839B52E38B4E2D574E7A1AF6A5439BF0B77EB93EC1",
"hide-old-entry.min.js": "82C5BB63906A244E1A8CAF2162F502A31188E8437387829B4AC9950E8836100E", "hide-old-entry.min.js": "82C5BB63906A244E1A8CAF2162F502A31188E8437387829B4AC9950E8836100E",
"hide-top-search.min.js": "19641CCB6A883DB5DD143A768606DEF0C571572D91CCD3FD5A9302A2A916E19B", "hide-top-search.min.js": "19641CCB6A883DB5DD143A768606DEF0C571572D91CCD3FD5A9302A2A916E19B",
"home-video.vue.min.js": "D59D70D527A4F6769A5E04A760FCE6C62E8B69CDFCEA5CDEC6338D19261FE7E0", "home-video.vue.min.js": "9CA2EF60468CF376E5FB6EB8DC55703A07C09D8197FD53AA3D43B131AE37BBAA",
"i18n.de-DE.min.js": "5BDAC5F0493F447A98B4D308817B21AB2787BEF9E3929EA37F0D2ACD3D879337", "i18n.de-DE.min.js": "5BDAC5F0493F447A98B4D308817B21AB2787BEF9E3929EA37F0D2ACD3D879337",
"i18n.en-US.min.js": "9DF9263CB0D4CA8FDB17A75F6ECA0D48F8B34540947C70C4FEA0403613DD1C43", "i18n.en-US.min.js": "9DF9263CB0D4CA8FDB17A75F6ECA0D48F8B34540947C70C4FEA0403613DD1C43",
"i18n.ja-JP.min.js": "9D924D58A6CD265EB95DA29B7E64885CD74089EC14A07C36CF3EAF42C8BEE33B", "i18n.ja-JP.min.js": "9D924D58A6CD265EB95DA29B7E64885CD74089EC14A07C36CF3EAF42C8BEE33B",
@ -85,7 +85,7 @@
"medal-helper.min.css": "205A02CC6E8B2DBDA222A0660D83EA6E4B24F0B5A753E269FED099AB8AE31B6C", "medal-helper.min.css": "205A02CC6E8B2DBDA222A0660D83EA6E4B24F0B5A753E269FED099AB8AE31B6C",
"medal-helper.min.html": "5D7057259368BE97DED3375DD904695B245AA2BF338C5E18CB3CF61DD913617C", "medal-helper.min.html": "5D7057259368BE97DED3375DD904695B245AA2BF338C5E18CB3CF61DD913617C",
"medal-helper.min.js": "33751914C5DE205D79E059F7BF285E325E4D6DBFC68AE7E4D4B6307672F23B6E", "medal-helper.min.js": "33751914C5DE205D79E059F7BF285E325E4D6DBFC68AE7E4D4B6307672F23B6E",
"minimal-home.vue.min.js": "7F610F3C3812BC82005E8031B6597D7516D36BEB5FA2900B0385176D50483DCD", "minimal-home.vue.min.js": "B22CB38E0340256B773EE9FFF7F673BE6A8ABA9B66174BCB650AF5D98B24A558",
"narrow-danmaku.min.js": "12475431A527EFF15100AF57C9C53D0603BC27723126D966CB01240917602253", "narrow-danmaku.min.js": "12475431A527EFF15100AF57C9C53D0603BC27723126D966CB01240917602253",
"new-styles.min.js": "3D7E8E25C5B5B6BD3F784BC05D403C35F0658E67197F878874A9554C2FF5127B", "new-styles.min.js": "3D7E8E25C5B5B6BD3F784BC05D403C35F0658E67197F878874A9554C2FF5127B",
"no-banner.min.css": "DA096F94E7FA26992F3F71245E704D69A1C222D0ADA6F1990FA5D948507CE15F", "no-banner.min.css": "DA096F94E7FA26992F3F71245E704D69A1C222D0ADA6F1990FA5D948507CE15F",
@ -100,6 +100,7 @@
"override-navbar.min.js": "5EC6A7D1D2ADE38FEA0BDE3FBBDB5A4054A05FE2FC386FB3339CD9AD3AF7F4DE", "override-navbar.min.js": "5EC6A7D1D2ADE38FEA0BDE3FBBDB5A4054A05FE2FC386FB3339CD9AD3AF7F4DE",
"player-focus.min.js": "2C849315D6FE5968908ACC2F0CD6252C8D5988485B10C1FD09C96D2E397FD30D", "player-focus.min.js": "2C849315D6FE5968908ACC2F0CD6252C8D5988485B10C1FD09C96D2E397FD30D",
"player-shadow.min.js": "918D2127907BC2C164CB86BF7F9C2501CF3B9CD236FEEDE5155B9B5D932F3415", "player-shadow.min.js": "918D2127907BC2C164CB86BF7F9C2501CF3B9CD236FEEDE5155B9B5D932F3415",
"rank-list.vue.min.js": "51CC28C7D4FB94D69CE02602779DE2D0793791FA8D18B2DA94BC298B98FDCC40",
"remove-promotions.min.css": "FC6AA1EE75AFD8C82E8AFBC68FD898364AD8EB3720503B1A7A613CAB2B38C5EC", "remove-promotions.min.css": "FC6AA1EE75AFD8C82E8AFBC68FD898364AD8EB3720503B1A7A613CAB2B38C5EC",
"remove-promotions.min.js": "A10C64F78511BC75B9BBA2DFFEBF7FCC4C6C505EF2F75DC0C7AFEF3E162BEA1E", "remove-promotions.min.js": "A10C64F78511BC75B9BBA2DFFEBF7FCC4C6C505EF2F75DC0C7AFEF3E162BEA1E",
"remove-top-mask.min.js": "A15C1EC10D2E1A61845B1ADAE51860553F96427059E10443B1E53FAF48F45304", "remove-top-mask.min.js": "A15C1EC10D2E1A61845B1ADAE51860553F96427059E10443B1E53FAF48F45304",
@ -139,6 +140,7 @@
"tweets.min.css": "9015C1F165C91B9205ABBE4E8A3B5FA83DB1EB4B5CF2442846AF61E44FF178A8", "tweets.min.css": "9015C1F165C91B9205ABBE4E8A3B5FA83DB1EB4B5CF2442846AF61E44FF178A8",
"v-checkbox.vue.min.js": "A23C35D5627009A29FD396A024442A19E37DEE70674BF3CE0FA377D781ED2231", "v-checkbox.vue.min.js": "A23C35D5627009A29FD396A024442A19E37DEE70674BF3CE0FA377D781ED2231",
"v-dropdown.vue.min.js": "66C883695F6653412980050A23F7581557407A2859214BF0CAAEC7001D0B5DDB", "v-dropdown.vue.min.js": "66C883695F6653412980050A23F7581557407A2859214BF0CAAEC7001D0B5DDB",
"video-card.vue.min.js": "22685DF32E1B294F5BB13D91E05A941A2543F4DE8B168275AAE1D62FB717A781",
"video-info.min.js": "7234A74CA28A772A31E41BBD4925FC2B22C6701419ADFD511402C6A9D6D9E5FA", "video-info.min.js": "7234A74CA28A772A31E41BBD4925FC2B22C6701419ADFD511402C6A9D6D9E5FA",
"video-story.min.js": "F9D4D2D80997DF5F11BF0CFA4D389B77BDBF1566EA6002E47174B68B440F3C0D", "video-story.min.js": "F9D4D2D80997DF5F11BF0CFA4D389B77BDBF1566EA6002E47174B68B440F3C0D",
"view-cover.min.js": "C458AD430FB767111D2F8E1F63BF85C3047FC7FDDED82D00C0D8EEA9542BD945", "view-cover.min.js": "C458AD430FB767111D2F8E1F63BF85C3047FC7FDDED82D00C0D8EEA9542BD945",

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
(()=>{return(a,e)=>{const i=`<div class=minimal-home><div class=minimal-home-header><icon class=logo icon=logo type=main></icon><div class=home-tabs><div v-for="(tab, index) of tabs":key=index class=tab :class="{active: tab.active}":data-tab=tab.name @click=changeTab(tab)>{{tab.displayName}}</div></div></div><div class=minimal-home-content><component :is=content></component></div></div>`;e.applyStyleFromText(`.minimal-home{--card-width:600px;--card-height:120px;--card-margin:16px;--card-column-count:2;transform:translateX(calc(var(--card-margin)/ 2))}.minimal-home,.minimal-home *{box-sizing:border-box;transition:.2s ease-out}.minimal-home .logo{font-size:48px;color:var(--theme-color)}.minimal-home .minimal-home-header{display:flex;align-items:center;justify-content:space-between}.minimal-home .minimal-home-header .home-tabs{display:flex;flex-grow:1;justify-content:flex-end;margin-right:var(--card-margin)}.minimal-home .minimal-home-header .home-tabs .tab{color:#707070;opacity:.75;position:relative;cursor:pointer;margin-left:32px}body.dark .minimal-home .minimal-home-header .home-tabs .tab{color:#eee}.minimal-home .minimal-home-header .home-tabs .tab.active{transform:scale(1.2);opacity:1;font-weight:700}.minimal-home .minimal-home-header .home-tabs .tab::after{content:"";position:absolute;bottom:-8px;left:50%;transform:translateX(-50%) scaleX(0);height:3px;width:24px;background-color:var(--theme-color);border-radius:2px;transition:.2s ease-out}.minimal-home .minimal-home-header .home-tabs .tab.active::after{transform:translateX(-50%) scaleX(1)}.minimal-home .minimal-home-content{margin-top:32px;width:calc(var(--card-column-count) * (var(--card-width) + var(--card-margin)))}@media screen and (max-width:1300px){.minimal-home{--card-column-count:1}}`,"minimal-home-style");return{export:Object.assign({template:i},{components:{Icon:()=>e.importAsync("icon.vue"),HomeVideo:()=>e.importAsync("home-video.vue")},data(){return{tabs:[{name:"video",displayName:"视频动态",active:true,more:"https://t.bilibili.com/?tab=8"},{name:"ranking7",displayName:"一周排行",active:false,more:"https://www.bilibili.com/ranking/all/0/0/7"},{name:"ranking3",displayName:"三日排行",active:false,more:"https://www.bilibili.com/ranking"},{name:"ranking1",displayName:"昨日排行",active:false,more:"https://www.bilibili.com/ranking/all/0/0/1"}],content:"HomeVideo"}},methods:{changeTab(a){if(a.active){window.open(a.more,"_blank");return}const e=this.tabs.find(a=>a.active);e.active=false;a.active=true}}})}}})(); (()=>{return(a,e)=>{const i=`<div class=minimal-home><div class=minimal-home-header><icon class=logo icon=logo type=main></icon><div class=home-tabs><div v-for="(tab, index) of tabs":key=index class=tab :class="{active: tab.active}":data-tab=tab.name @click=changeTab(tab)>{{tab.displayName}}</div></div></div><div class=minimal-home-content><component :is=content :key=activeTab.name :rank-days=rankDays></component></div></div>`;e.applyStyleFromText(`.minimal-home{--card-width:600px;--card-height:120px;--card-margin:16px;--card-column-count:2;transform:translateX(calc(var(--card-margin)/ 2))}.minimal-home,.minimal-home *{box-sizing:border-box;transition:.2s ease-out}.minimal-home .logo{font-size:48px;color:var(--theme-color)}.minimal-home .minimal-home-header{display:flex;align-items:center;justify-content:space-between}.minimal-home .minimal-home-header .home-tabs{display:flex;flex-grow:1;justify-content:flex-end;margin-right:var(--card-margin)}.minimal-home .minimal-home-header .home-tabs .tab{color:#707070;opacity:.75;position:relative;cursor:pointer;margin-left:32px}body.dark .minimal-home .minimal-home-header .home-tabs .tab{color:#eee}.minimal-home .minimal-home-header .home-tabs .tab.active{transform:scale(1.2);opacity:1;font-weight:700}.minimal-home .minimal-home-header .home-tabs .tab::after{content:"";position:absolute;bottom:-8px;left:50%;transform:translateX(-50%) scaleX(0);height:3px;width:24px;background-color:var(--theme-color);border-radius:2px;transition:.2s ease-out}.minimal-home .minimal-home-header .home-tabs .tab.active::after{transform:translateX(-50%) scaleX(1)}.minimal-home .minimal-home-content{margin-top:32px;width:calc(var(--card-column-count) * (var(--card-width) + var(--card-margin)))}@media screen and (max-width:1300px){.minimal-home{--card-column-count:1}}`,"minimal-home-style");const t=[{name:"video",displayName:"视频动态",active:true,more:"https://t.bilibili.com/?tab=8"},{name:"ranking7",displayName:"一周排行",active:false,more:"https://www.bilibili.com/ranking/all/0/0/7",rankDays:7},{name:"ranking3",displayName:"三日排行",active:false,more:"https://www.bilibili.com/ranking",rankDays:3},{name:"ranking1",displayName:"昨日排行",active:false,more:"https://www.bilibili.com/ranking/all/0/0/1",rankDays:1}];return{export:Object.assign({template:i},{components:{Icon:()=>e.importAsync("icon.vue"),HomeVideo:()=>e.importAsync("home-video.vue"),RankList:()=>e.importAsync("rank-list.vue")},data(){return{tabs:t,content:"HomeVideo"}},computed:{activeTab(){return this.tabs.find(a=>a.active)},rankDays(){return this.activeTab.rankDays||0}},methods:{changeTab(a){if(a.active){window.open(a.more,"_blank");return}const e=this.activeTab;e.active=false;a.active=true;this.content=a.name==="video"?"HomeVideo":"RankList"}}})}}})();

1
min/rank-list.vue.min.js vendored Normal file
View File

@ -0,0 +1 @@
(()=>{return(t,r)=>{const e=`<div class=rank-list>wryyyy</div>`;return{export:Object.assign({template:e},{})}}})();

1
min/video-card.vue.min.js vendored Normal file
View File

@ -0,0 +1 @@
(()=>{return(e,i)=>{const t=`<a class=video-card target=_blank :href="'https://www.bilibili.com/av' + aid"><div class=cover-container><dpi-img class=cover :src=coverUrl :size="{height: 120, width: 200}"></dpi-img><div class=duration>{{durationText}}</div><div class=watchlater @click.stop.prevent=toggleWatchlater()><i class=mdi :class="{'mdi-clock-outline': !watchlater, 'mdi-check-circle': watchlater}"></i>{{watchlater ? '已添加' : '稍后再看'}}</div></div><h1 class=title :title=title>{{title}}</h1><div class=topics v-if="topics && topics.length"><a class=topic v-for="topic of topics":key=topic.id target=_blank :href="'https://t.bilibili.com/topic/name/' + topic.name + '/feed'">#{{topic.name}}#</a></div><pre class="description single-line":title=description v-else>{{description}}</pre><a class=up :class="{'no-face': !upFaceUrl}"target=_blank :href="'https://space.bilibili.com/' + upID"><dpi-img v-if=upFaceUrl class=face :src=upFaceUrl :size=24></dpi-img><icon v-else icon=up type=extended></icon><div class=name :title=upName>{{upName}}</div></a><div class=stats><template v-if=like><icon type=extended icon=like></icon>{{like}}</template><icon type=extended icon=play></icon>{{playCount}}<template v-if=danmakuCount><icon type=extended icon=danmaku></icon>{{danmakuCount}}</template></div></a>`;i.applyStyleFromText(`.video-card{display:grid;grid-template-columns:200px 1fr;grid-template-rows:3fr 2fr 3fr;grid-template-areas:"cover title" "cover description" "cover up";height:var(--card-height);width:var(--card-width);color:#000;border-radius:16px;box-shadow:0 2px 6px 0 #0002;margin-right:var(--card-margin);margin-bottom:var(--card-margin)}body.dark .video-card{background-color:#282828;color:#fff}.video-card>*{justify-self:self-start;align-self:center}.video-card:hover{transform:scale(1.02);transition:.1s cubic-bezier(.39,.58,.57,1)}.video-card:hover .duration,.video-card:hover .watchlater{opacity:1}.video-card .duration,.video-card .watchlater{opacity:0}.video-card .cover-container{grid-area:cover;position:relative}.video-card .cover-container .cover{border-radius:16px 0 0 16px;object-fit:cover}.video-card .cover-container>:not(.cover){position:absolute}.video-card .cover-container .duration,.video-card .cover-container .watchlater{bottom:6px;padding:4px 8px;background-color:#000a;color:#fff;border-radius:14px;height:24px}.video-card .cover-container .duration .mdi,.video-card .cover-container .watchlater .mdi{font-size:12pt;line-height:1;margin-right:4px}.video-card .cover-container .duration{left:6px}.video-card .cover-container .watchlater{right:6px;display:flex;align-items:center;padding-left:4px}.video-card .title{grid-area:title;font-size:12pt;font-weight:700;color:inherit;padding:0 12px;white-space:nowrap;overflow:hidden;justify-self:stretch;text-overflow:ellipsis}.video-card .topics{grid-area:description;display:flex;align-items:center;margin-left:12px}.video-card .topics .topic{color:inherit;padding:4px 8px;background-color:#8882;margin-right:8px;border-radius:14px}.video-card .description{grid-area:description;color:inherit;overflow:auto;align-self:stretch;justify-self:stretch;margin:0 12px;white-space:pre-wrap;line-height:1.5;scrollbar-width:none!important}.video-card .description::-webkit-scrollbar{width:0!important}.video-card .description.single-line{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.video-card .stats,.video-card .up{grid-area:up}.video-card .up{margin-left:12px;display:flex;align-items:center;padding:2px;background-color:#8882;border-radius:14px;color:inherit}.video-card .up .face{border-radius:50%}.video-card .up .name{margin:0 8px}.video-card .up:hover .name{color:var(--theme-color)}.video-card .stats{justify-self:self-end;margin-right:12px;display:flex;align-items:center;opacity:.5}.video-card .stats .be-icon{font-size:12pt;margin:0 4px 0 12px}`,"video-card-style");return{export:Object.assign({template:t},{props:["data"],components:{"dpi-img":()=>i.importAsync("dpi-img.vue"),Icon:()=>i.importAsync("icon.vue")},data(){return{...this.data}},methods:{async toggleWatchlater(){try{this.watchlater=!this.watchlater;const{toggleWatchlater:e}=await i.importAsync("watchlater-api");e(this.aid.toString(),this.watchlater)}catch(e){this.watchlater=!this.watchlater;Toast.error(e.message,"稍后再看操作失败",3e3)}}}})}}})();

View File

@ -4,103 +4,24 @@
<i class="mdi mdi-18px mdi-loading mdi-spin"></i>加载中... <i class="mdi mdi-18px mdi-loading mdi-spin"></i>加载中...
</div> </div>
<div class="cards" v-else-if="cards.length"> <div class="cards" v-else-if="cards.length">
<a <video-card v-for="card of cards" :key="card.id" :data="card"></video-card>
class="home-video-card"
v-for="card in cards"
:key="card.id"
target="_blank"
:href="'https://www.bilibili.com/av' + card.aid"
>
<div class="cover-container">
<dpi-img class="cover" :src="card.coverUrl" :size="{height: 120, width: 200}"></dpi-img>
<div class="duration">{{card.durationText}}</div>
<div class="watchlater" @click.stop.prevent="watchlater(card.id)">
<i
class="mdi"
:class="{'mdi-clock-outline': !card.watchlater, 'mdi-check-circle': card.watchlater}"
></i>
{{card.watchlater ? '已添加' : '稍后再看'}}
</div>
</div>
<h1 class="title" :title="card.title">{{card.title}}</h1>
<div class="topics" v-if="card.topics.length">
<a
class="topic"
v-for="topic of card.topics"
:key="topic.id"
target="_blank"
:href="'https://t.bilibili.com/topic/name/' + topic.name + '/feed'"
>#{{topic.name}}#</a>
</div>
<pre class="description single-line" :title="card.description" v-else>{{card.description}}</pre>
<a class="up" target="_blank" :href="'https://space.bilibili.com/' + card.upID">
<dpi-img class="face" :src="card.upFaceUrl" :size="24"></dpi-img>
<div class="name" :title="card.upName">{{card.upName}}</div>
</a>
<div class="stats">
<Icon type="extended" icon="like"></Icon>
{{card.like}}
<Icon type="extended" icon="play"></Icon>
{{card.playCount}}
<Icon type="extended" icon="danmaku"></Icon>
{{card.danmakuCount}}
</div>
</a>
</div> </div>
<div class="empty" v-else>空空如也哦 =ω=</div> <div class="empty" v-else>空空如也哦 =ω=</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
interface VideoCard { import { VideoCardInfo } from '../video-card.vue'
id: string
aid: number
title: string
upID: number
upName: string
upFaceUrl: string
coverUrl: string
description: string
duration: number
durationText: string
playCount: string
danmakuCount: string
dynamic: string
like: string
timestamp: number
time: Date
topics: {
id: number
name: string
}[]
watchlater: boolean
}
export default { export default {
components: { components: {
'dpi-img': () => import('../../dpi-img.vue'), VideoCard: () => import('../video-card.vue'),
Icon: () => import('../../icon.vue')
}, },
data() { data() {
return { return {
cards: [] as VideoCard[], cards: [] as VideoCardInfo[],
loading: true loading: true
} }
}, },
methods: {
async watchlater(id: string) {
const card = this.cards.find((it: VideoCard) => it.id === id) as VideoCard
try {
card.watchlater = !card.watchlater
const { toggleWatchlater } = await import(
'../../../video/watchlater-api'
)
toggleWatchlater(card.aid.toString(), card.watchlater)
} catch (error) {
card.watchlater = !card.watchlater
Toast.error(error.message, '稍后再看操作失败', 3000)
}
}
},
async mounted() { async mounted() {
try { try {
const json = await Ajax.getJsonWithCredentials( const json = await Ajax.getJsonWithCredentials(
@ -114,7 +35,7 @@ export default {
throw new Error(json.message) throw new Error(json.message)
} }
this.cards = json.data.cards.map( this.cards = json.data.cards.map(
(c: any): VideoCard => { (c: any): VideoCardInfo => {
const card = JSON.parse(c.card) const card = JSON.parse(c.card)
const topics = _.get(c, 'display.topic_info.topic_details', []).map( const topics = _.get(c, 'display.topic_info.topic_details', []).map(
(it: any) => { (it: any) => {
@ -160,157 +81,6 @@ export default {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
.home-video-card {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 3fr 2fr 3fr;
grid-template-areas:
'cover title'
'cover description'
'cover up';
height: var(--card-height);
width: var(--card-width);
color: black;
border-radius: 16px;
box-shadow: 0 2px 6px 0 #0002;
margin-right: var(--card-margin);
margin-bottom: var(--card-margin);
body.dark & {
background-color: #282828;
color: white;
}
& > * {
justify-self: self-start;
align-self: center;
}
&:hover {
transform: scale(1.02);
transition: 0.1s cubic-bezier(0.39, 0.58, 0.57, 1);
.duration,
.watchlater {
opacity: 1;
}
}
.duration,
.watchlater {
opacity: 0;
}
.cover-container {
grid-area: cover;
position: relative;
.cover {
border-radius: 16px 0 0 16px;
object-fit: cover;
}
& > :not(.cover) {
position: absolute;
}
.duration,
.watchlater {
bottom: 6px;
padding: 4px 8px;
background-color: #000a;
color: white;
border-radius: 14px;
height: 24px;
.mdi {
font-size: 12pt;
line-height: 1;
margin-right: 4px;
}
}
.duration {
left: 6px;
}
.watchlater {
right: 6px;
display: flex;
align-items: center;
padding-left: 4px;
}
}
.title {
grid-area: title;
font-size: 12pt;
font-weight: bold;
color: inherit;
padding: 0 12px;
white-space: nowrap;
overflow: hidden;
justify-self: stretch;
text-overflow: ellipsis;
}
.topics {
grid-area: description;
display: flex;
align-items: center;
margin-left: 12px;
.topic {
color: inherit;
padding: 4px 8px;
background-color: #8882;
margin-right: 8px;
border-radius: 14px;
}
}
.description {
grid-area: description;
color: inherit;
overflow: auto;
align-self: stretch;
justify-self: stretch;
margin: 0 12px;
white-space: pre-wrap;
line-height: 1.5;
scrollbar-width: none !important;
&::-webkit-scrollbar {
width: 0px !important;
}
&.single-line {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.up,
.stats {
grid-area: up;
}
.up {
margin-left: 12px;
display: flex;
align-items: center;
padding: 2px;
background-color: #8882;
border-radius: 14px;
color: inherit;
.face {
border-radius: 50%;
}
.name {
margin: 0 8px;
}
&:hover .name {
color: var(--theme-color);
}
}
.stats {
justify-self: self-end;
margin-right: 12px;
display: flex;
align-items: center;
opacity: 0.5;
.be-icon {
font-size: 12pt;
margin: 0 4px 0 12px;
}
}
}
} }
} }
</style> </style>

View File

@ -15,7 +15,7 @@
<!-- <Search></Search> --> <!-- <Search></Search> -->
</div> </div>
<div class="minimal-home-content"> <div class="minimal-home-content">
<component :is="content"></component> <component :is="content" :key="activeTab.name" :rank-days="rankDays"></component>
</div> </div>
</div> </div>
</template> </template>
@ -27,16 +27,9 @@ interface Tab {
displayName: string displayName: string
active: boolean active: boolean
more: string more: string
rankDays?: number
} }
export default { const tabs = [
components: {
Icon: () => import('../../icon.vue'),
// Search: () => import('../../search.vue'),
HomeVideo: () => import('./home-video.vue')
},
data() {
return {
tabs: [
{ {
name: 'video', name: 'video',
displayName: '视频动态', displayName: '视频动态',
@ -47,33 +40,55 @@ export default {
name: 'ranking7', name: 'ranking7',
displayName: '一周排行', displayName: '一周排行',
active: false, active: false,
more: 'https://www.bilibili.com/ranking/all/0/0/7' more: 'https://www.bilibili.com/ranking/all/0/0/7',
rankDays: 7
}, },
{ {
name: 'ranking3', name: 'ranking3',
displayName: '三日排行', displayName: '三日排行',
active: false, active: false,
more: 'https://www.bilibili.com/ranking' more: 'https://www.bilibili.com/ranking',
rankDays: 3
}, },
{ {
name: 'ranking1', name: 'ranking1',
displayName: '昨日排行', displayName: '昨日排行',
active: false, active: false,
more: 'https://www.bilibili.com/ranking/all/0/0/1' more: 'https://www.bilibili.com/ranking/all/0/0/1',
rankDays: 1
} }
] as Tab[], ] as Tab[]
export default {
components: {
Icon: () => import('../../icon.vue'),
// Search: () => import('../../search.vue'),
HomeVideo: () => import('./home-video.vue'),
RankList: () => import('./rank-list.vue')
},
data() {
return {
tabs,
content: 'HomeVideo' content: 'HomeVideo'
} }
}, },
computed: {
activeTab() {
return this.tabs.find((t: Tab) => t.active) as Tab
},
rankDays(): number {
return this.activeTab.rankDays || 0
}
},
methods: { methods: {
changeTab(tab: Tab) { changeTab(tab: Tab) {
if (tab.active) { if (tab.active) {
window.open(tab.more, '_blank') window.open(tab.more, '_blank')
return return
} }
const activeTab = this.tabs.find((t: Tab) => t.active) as Tab const activeTab = this.activeTab
activeTab.active = false activeTab.active = false
tab.active = true tab.active = true
this.content = tab.name === 'video' ? 'HomeVideo' : 'RankList'
} }
} }
} }

View File

@ -0,0 +1,18 @@
<template>
<div class="rank-list">
<!-- <div class="loading" v-if="loading">
<i class="mdi mdi-18px mdi-loading mdi-spin"></i>加载中...
</div>
<div class="cards" v-else-if="cards.length">
</div>
<div class="empty" v-else>空空如也哦 =ω=</div> -->
wryyyy
</div>
</template>
<script lang="ts">
export default {
}
</script>

View File

@ -0,0 +1,249 @@
<template>
<a class="video-card" target="_blank" :href="'https://www.bilibili.com/av' + aid">
<div class="cover-container">
<dpi-img class="cover" :src="coverUrl" :size="{height: 120, width: 200}"></dpi-img>
<div class="duration">{{durationText}}</div>
<div class="watchlater" @click.stop.prevent="toggleWatchlater()">
<i class="mdi" :class="{'mdi-clock-outline': !watchlater, 'mdi-check-circle': watchlater}"></i>
{{watchlater ? '已添加' : '稍后再看'}}
</div>
</div>
<h1 class="title" :title="title">{{title}}</h1>
<div class="topics" v-if="topics && topics.length">
<a
class="topic"
v-for="topic of topics"
:key="topic.id"
target="_blank"
:href="'https://t.bilibili.com/topic/name/' + topic.name + '/feed'"
>#{{topic.name}}#</a>
</div>
<pre class="description single-line" :title="description" v-else>{{description}}</pre>
<a
class="up"
:class="{'no-face': !upFaceUrl}"
target="_blank"
:href="'https://space.bilibili.com/' + upID"
>
<dpi-img v-if="upFaceUrl" class="face" :src="upFaceUrl" :size="24"></dpi-img>
<Icon v-else icon="up" type="extended"></Icon>
<div class="name" :title="upName">{{upName}}</div>
</a>
<div class="stats">
<template v-if="like">
<Icon type="extended" icon="like"></Icon>
{{like}}
</template>
<Icon type="extended" icon="play"></Icon>
{{playCount}}
<template v-if="danmakuCount">
<Icon type="extended" icon="danmaku"></Icon>
{{danmakuCount}}
</template>
</div>
</a>
</template>
<script lang="ts">
export interface VideoCardInfo {
id: string
aid: number
title: string
upID: number
upName: string
upFaceUrl?: string
coverUrl: string
description: string
duration?: number
durationText: string
playCount: string
danmakuCount?: string
dynamic?: string
like?: string
coins?: string
timestamp?: number
time?: Date
topics?: {
id: number
name: string
}[]
watchlater: boolean
}
export default {
props: ['data'],
components: {
'dpi-img': () => import('../dpi-img.vue'),
Icon: () => import('../icon.vue')
},
data() {
return {
...this.data
} as VideoCardInfo
},
methods: {
async toggleWatchlater() {
try {
this.watchlater = !this.watchlater
const { toggleWatchlater: toggle } = await import('../../video/watchlater-api')
toggle(this.aid.toString(), this.watchlater)
} catch (error) {
this.watchlater = !this.watchlater
Toast.error(error.message, '稍后再看操作失败', 3000)
}
}
}
}
</script>
<style lang="scss">
.video-card {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 3fr 2fr 3fr;
grid-template-areas:
'cover title'
'cover description'
'cover up';
height: var(--card-height);
width: var(--card-width);
color: black;
border-radius: 16px;
box-shadow: 0 2px 6px 0 #0002;
margin-right: var(--card-margin);
margin-bottom: var(--card-margin);
body.dark & {
background-color: #282828;
color: white;
}
& > * {
justify-self: self-start;
align-self: center;
}
&:hover {
transform: scale(1.02);
transition: 0.1s cubic-bezier(0.39, 0.58, 0.57, 1);
.duration,
.watchlater {
opacity: 1;
}
}
.duration,
.watchlater {
opacity: 0;
}
.cover-container {
grid-area: cover;
position: relative;
.cover {
border-radius: 16px 0 0 16px;
object-fit: cover;
}
& > :not(.cover) {
position: absolute;
}
.duration,
.watchlater {
bottom: 6px;
padding: 4px 8px;
background-color: #000a;
color: white;
border-radius: 14px;
height: 24px;
.mdi {
font-size: 12pt;
line-height: 1;
margin-right: 4px;
}
}
.duration {
left: 6px;
}
.watchlater {
right: 6px;
display: flex;
align-items: center;
padding-left: 4px;
}
}
.title {
grid-area: title;
font-size: 12pt;
font-weight: bold;
color: inherit;
padding: 0 12px;
white-space: nowrap;
overflow: hidden;
justify-self: stretch;
text-overflow: ellipsis;
}
.topics {
grid-area: description;
display: flex;
align-items: center;
margin-left: 12px;
.topic {
color: inherit;
padding: 4px 8px;
background-color: #8882;
margin-right: 8px;
border-radius: 14px;
}
}
.description {
grid-area: description;
color: inherit;
overflow: auto;
align-self: stretch;
justify-self: stretch;
margin: 0 12px;
white-space: pre-wrap;
line-height: 1.5;
scrollbar-width: none !important;
&::-webkit-scrollbar {
width: 0px !important;
}
&.single-line {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.up,
.stats {
grid-area: up;
}
.up {
margin-left: 12px;
display: flex;
align-items: center;
padding: 2px;
background-color: #8882;
border-radius: 14px;
color: inherit;
.face {
border-radius: 50%;
}
.name {
margin: 0 8px;
}
&:hover .name {
color: var(--theme-color);
}
}
.stats {
justify-self: self-end;
margin-right: 12px;
display: flex;
align-items: center;
opacity: 0.5;
.be-icon {
font-size: 12pt;
margin: 0 4px 0 12px;
}
}
}
</style>