Rewrite list items :)

This commit is contained in:
Cadence Ember 2020-06-24 03:47:19 +12:00
parent dd2bfc6970
commit 7afbe836d3
No known key found for this signature in database
GPG Key ID: 128B99B1B74A6412
26 changed files with 376 additions and 568 deletions

7
.vscode/tasks.json vendored
View File

@ -7,6 +7,13 @@
"type": "npm",
"script": "dev",
"problemMatcher": []
},
{
"type": "npm",
"script": "dev-runner",
"problemMatcher": [],
"label": "npm: dev-runner",
"detail": "node _scripts/dev-runner.js"
}
]
}

View File

@ -0,0 +1,11 @@
import Vue from 'vue'
export default Vue.extend({
name: 'FtAutoGrid',
props: {
grid: {
type: Boolean,
required: true
}
}
})

View File

@ -0,0 +1,10 @@
.ft-auto-grid
&.grid
display: grid
grid-template-columns: repeat(auto-fill, 240px)
justify-content: space-evenly
grid-gap: 5px
&.list
display: grid
grid-gap: 16px

View File

@ -0,0 +1,14 @@
<template>
<div
class="ft-auto-grid"
:class="{
grid: grid,
list: !grid
}"
>
<slot />
</div>
</template>
<script src="./ft-auto-grid.js" />
<style scoped lang="sass" src="./ft-auto-grid.sass" />

View File

@ -1,6 +1,6 @@
import Vue from 'vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtGrid from '../ft-grid/ft-grid.vue'
import FtAutoGrid from '../ft-auto-grid/ft-auto-grid.vue'
import FtListVideo from '../ft-list-video/ft-list-video.vue'
import FtListChannel from '../ft-list-channel/ft-list-channel.vue'
import FtListPlaylist from '../ft-list-playlist/ft-list-playlist.vue'
@ -9,7 +9,7 @@ export default Vue.extend({
name: 'FtElementList',
components: {
'ft-flex-box': FtFlexBox,
'ft-grid': FtGrid,
'ft-auto-grid': FtAutoGrid,
'ft-list-video': FtListVideo,
'ft-list-channel': FtListChannel,
'ft-list-playlist': FtListPlaylist

View File

@ -1,49 +1,29 @@
<template>
<span>
<ft-flex-box
v-if="listType === 'list'"
<ft-auto-grid
:grid="listType !== 'list'"
>
<template
v-for="(result, index) in data"
>
<span
v-for="(result, index) in data"
<ft-list-channel
v-if="result.type === 'channel'"
:data="result"
:key="index"
class="maxWidth"
>
<ft-list-channel
v-if="result.type === 'channel'"
:data="result"
/>
<ft-list-video
v-if="result.type === 'video' || result.type === 'shortVideo'"
:data="result"
/>
<ft-list-playlist
v-if="result.type === 'playlist'"
:data="result"
/>
</span>
</ft-flex-box>
<ft-grid
v-else
>
<span
v-for="(result, index) in data"
/>
<ft-list-video
v-if="result.type === 'video' || result.type === 'shortVideo'"
appearance="result"
:data="result"
:key="index"
>
<ft-list-channel
v-if="result.type === 'channel'"
:data="result"
/>
<ft-list-video
v-if="result.type === 'video' || result.type === 'shortVideo'"
:data="result"
/>
<ft-list-playlist
v-if="result.type === 'playlist'"
:data="result"
/>
</span>
</ft-grid>
</span>
/>
<ft-list-playlist
v-if="result.type === 'playlist'"
appearance="result"
:data="result"
:key="index"
/>
</template>
</ft-auto-grid>
</template>
<script src="./ft-element-list.js" />

View File

@ -19,6 +19,14 @@ export default Vue.extend({
type: Boolean,
default: true
},
padding: {
type: Number,
default: 10
},
size: {
type: Number,
default: 20
},
forceDropdown: {
type: Boolean,
default: false

View File

@ -3,12 +3,11 @@
flex-flow: row wrap
justify-content: space-evenly
position: relative
user-select: none
.iconButton
width: 1em
height: 1em
padding: 10px
font-size: 20px
border-radius: 50%
cursor: pointer
transition: background 0.15s ease-out

View File

@ -10,6 +10,10 @@
secondary: theme === 'secondary',
shadow: useShadow
}"
:style="{
padding: padding + 'px',
fontSize: size + 'px'
}"
@click="handleIconClick"
/>
<div

View File

@ -1,106 +0,0 @@
.videoThumbnail {
position: relative;
cursor: pointer;
}
.videoCountContainer {
position: absolute;
top: 0px;
right: 0px;
width: 120px;
background-color: rgba(0,0,0,0.6);
color: #FFFFFF;
text-align: center;
font-size: 20px;
}
.videoCountContainer span {
position: absolute;
top: 40px;
left: 45px;
}
.playlistTitle {
font-weight: bold;
color: var(--title-color);
cursor: pointer;
}
.channelName {
color: var(--secondary-text-color);
cursor: pointer;
font-size: 14px;
}
.grid {
width: 240px;
height: 250px;
padding: 2px;
overflow: hidden;
}
.grid .videoThumbnail {
width: 100%;
height: 130px;
margin-bottom: -5px;
}
.grid .videoThumbnail img {
width: 100%;
height: 130px;
}
.grid .videoCountContainer {
height: 130px;
}
.grid .playlistTitle {
max-height: 75px;
overflow-y: hidden;
}
.grid .channelName {
width: 275px;
}
.list {
height: 140px;
width: 100%;
margin-left: 5px;
margin-top: 15px;
border-bottom: 1px solid var(--secondary-text-color);
}
.list .videoThumbnail {
float: left;
width: 240px;
height: 130px;
}
.list .videoThumbnail img {
width: 100%;
height: 130px;
}
.list .videoCountContainer {
height: 130px;
}
.list .playlistTitle {
margin-left: 250px;
margin-top: 5px;
margin-bottom: -10px;
}
.list .channelName {
margin-left: 250px;
width: 275px;
}
.list .description {
margin-left: 285px;
font-size: 13px;
color: var(--secondary-text-color);
height: 35px;
overflow: hidden;
}

View File

@ -6,6 +6,10 @@ export default Vue.extend({
data: {
type: Object,
required: true
},
appearance: {
type: String,
required: true
}
},
data: function () {
@ -58,14 +62,6 @@ export default Vue.extend({
this.channelLink = this.data.author.ref
this.playlistLink = this.data.link
this.videoCount = parseInt(this.data.length.split(' ')[0])
},
goToPlaylist: function (id) {
this.$router.push({ path: `/playlist/${id}` })
},
goToChannel: function (id) {
console.log(id)
}
}
})

View File

@ -0,0 +1 @@
@use "../../sass-partials/_ft-list-item"

View File

@ -1,38 +1,45 @@
<template>
<div
class="ft-list-video"
:appearance="appearance"
:class="{ list: listType === 'list', grid: listType === 'grid' }"
>
<div class="videoThumbnail">
<router-link
class="videoThumbnail"
:to="`/playlist/${playlistId}`"
>
<img
:src="thumbnail"
@click="goToPlaylist(playlistId)"
class="thumbnailImage"
>
<div
class="videoCountContainer"
@click="goToPlaylist(playlistId)"
>
<span>
{{ videoCount }}
<br>
<font-awesome-icon icon="list" />
</span>
<div class="background" />
<div class="inner">
<div>{{ videoCount }}</div>
<div><font-awesome-icon icon="list" /></div>
</div>
</div>
</router-link>
<div class="videoInfo">
<router-link
class="title"
:to="`/playlist/${playlistId}`"
>
{{ title }}
</router-link>
<div class="infoLine">
<router-link
class="channelName"
:to="`/channel/${channelId}`"
>
{{ channelName }}
</router-link>
</div>
</div>
<p
class="playlistTitle"
@click="goToPlaylist(playlistId)"
>
{{ title }}
</p>
<p
class="channelName"
@click="goToChannel(channelId)"
>
{{ channelName }}
</p>
</div>
</template>
<script src="./ft-list-playlist.js" />
<style scoped src="./ft-list-playlist.css" />
<style scoped lang="sass" src="./ft-list-playlist.sass" />

View File

@ -1,247 +0,0 @@
.videoThumbnail {
position: relative;
cursor: pointer;
}
.videoThumbnail:hover .videoWatched {
visibility: hidden;
}
.favoritesIcon {
position: absolute;
font-size: 15px;
top: 0px;
right: 0px;
color: #FFFFFF;
padding: 5px;
background-color: #000000;
opacity: 0.7;
cursor: pointer;
}
.favorited {
color: yellow;
}
.videoDuration {
position: absolute;
font-size: 13px;
bottom: -7px;
right: 0px;
color: #FFFFFF;
padding: 2px;
background-color: #000000;
opacity: 0.7;
cursor: pointer;
}
.videoWatched {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
background-color: rgba(0,0,0,0.4);
color: #FFFFFF;
pointer-events: none;
}
.watchedProgressBar {
background-color: var(--red-500);
opacity: 0.8;
height: 3px;
position: absolute;
bottom: 0px;
left: 0px;
cursor: pointer;
}
.videoTitle {
color: var(--title-color);
font-weight: bold;
cursor: pointer;
}
.channelName {
color: var(--secondary-text-color);
cursor: pointer;
font-size: 14px;
}
.viewCount {
cursor: pointer;
font-size: 13px;
}
.uploadedTime {
cursor: pointer;
font-size: 13px;
}
.liveText {
color: var(--red-500);
font-size: 13px;
cursor: pointer;
}
/deep/ .iconButton {
font-size: 15px;
padding: 8px;
}
/deep/ .iconDropdown {
margin-top: 30px;
}
.grid {
width: 240px;
height: 250px;
padding: 2px;
overflow: hidden;
}
.grid .videoThumbnail {
width: 100%;
height: 130px;
margin-bottom: -5px;
}
.grid .videoThumbnail img {
width: 100%;
height: 130px;
}
.grid .videoWatched {
height: 110px;
}
.grid .optionsButton {
margin-top: 10px;
margin-left: 210px;
position: absolute;
}
.grid .videoTitle {
max-height: 55px;
width: 210px;
overflow-y: hidden;
margin-bottom: -15px;
}
.grid .channelName {
width: 220px;
height: 17px;
margin-bottom: 10px;
overflow-y: hidden;
}
.grid .liveText {
float: right;
}
.list {
height: 140px;
width: 100%;
margin-left: 5px;
margin-top: 15px;
}
.list .videoThumbnail {
float: left;
width: 240px;
height: 130px;
}
.list .videoThumbnail img {
width: 100%;
height: 130px;
}
.list .videoWatched {
height: 130px;
}
.list .optionsButton {
float: right;
}
.list .videoTitle {
margin-left: 250px;
margin-top: 5px;
margin-bottom: -10px;
}
.list .channelName {
margin-left: 250px;
max-width: 275px;
}
.list .viewCount {
margin-left: 10px;
}
.list .liveText {
margin-left: 10px;
}
.list .description {
margin-left: 250px;
font-size: 13px;
color: var(--secondary-text-color);
height: 35px;
overflow: hidden;
}
.videoRecommendation.list {
height: 110px;
}
.videoRecommendation.list .videoThumbnail {
width: 180px;
height: 100px;
}
.videoRecommendation.list .videoThumbnail img {
height: 100px;
}
.videoRecommendation.list .videoTitle {
font-size: 12px;
margin-left: 185px;
}
.videoRecommendation.list .channelName {
margin-left: 185px;
}
.videoRecommendation.list .viewCount {
margin-left: 5px;
}
.playlistItem .list {
height: 60px;
width: calc(100% - 30px);
}
.playlistItem .list .videoThumbnail {
width: 100px;
height: 60px;
}
.playlistItem .list .videoThumbnail img {
height: 60px;
}
.playlistItem .list .videoTitle {
font-size: 12px;
margin-left: 105px;
margin-right: 30px;
}
.playlistItem .list .channelName {
margin-left: 105px;
margin-right: 30px;
}
.playlistItem .list .viewCount {
margin-left: 5px;
}

View File

@ -1,10 +1,12 @@
import Vue from 'vue'
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
import FtCard from "../ft-card/ft-card.vue"
export default Vue.extend({
name: 'FtListVideo',
components: {
'ft-icon-button': FtIconButton
'ft-icon-button': FtIconButton,
'ft-card': FtCard
},
props: {
data: {
@ -18,6 +20,10 @@ export default Vue.extend({
forceListType: {
type: String,
default: null
},
appearance: {
type: String,
required: true
}
},
data: function () {
@ -120,31 +126,6 @@ export default Vue.extend({
}
},
methods: {
play: function () {
const playlistInfo = {
playlistId: this.playlistId
}
console.log('playlist info')
console.log(playlistInfo)
if (this.playlistId !== null) {
console.log('Sending playlist info')
this.$router.push(
{
path: `/watch/${this.id}`,
query: playlistInfo
}
)
} else {
console.log('no playlist found')
this.$router.push({ path: `/watch/${this.id}` })
}
},
goToChannel: function () {
this.$router.push({ path: `/channel/${this.channelId}` })
},
toggleSave: function () {
console.log('TODO: ft-list-video method toggleSave')
},

View File

@ -0,0 +1 @@
@use "../../sass-partials/_ft-list-item"

View File

@ -3,25 +3,37 @@
class="ft-list-video"
:class="{
list: (listType === 'list' || forceListType === 'list') && forceListType !== 'grid',
grid: (listType === 'grid' || forceListType === 'list') && forceListType !== 'list'
grid: (listType === 'grid' || forceListType === 'list') && forceListType !== 'list',
[appearance]: true
}"
>
<div class="videoThumbnail">
<img
:src="thumbnail"
@click="play(id)"
<div
class="videoThumbnail"
>
<router-link
class="thumbnailLink"
:to="{
path: `/watch/${id}`,
query: playlistId ? {playlistId} : {}
}"
>
<p
v-if="!isLive"
<img
:src="thumbnail"
class="thumbnailImage"
>
</router-link>
<div
class="videoDuration"
@click="play(id)"
:class="{ live: isLive }"
>
{{ duration }}
</p>
<font-awesome-icon
{{ isLive ? "Live" : duration }}
</div>
<ft-icon-button
v-if="!isLive"
icon="star"
class="favoritesIcon"
:padding="6"
:size="18"
:class="{ favorited: isFavorited }"
@click="toggleSave(id)"
/>
@ -29,7 +41,7 @@
v-if="watched"
class="videoWatched"
>
WATCHED
Watched
</div>
<div
v-if="watched"
@ -37,65 +49,42 @@
:style="{width: progressPercentage + '%'}"
/>
</div>
<ft-icon-button
class="optionsButton"
title="More Options"
theme="base"
:use-shadow="false"
dropdown-position-x="left"
:dropdown-names="optionsNames"
:dropdown-values="optionsValues"
@click="handleOptionsClick"
/>
<p
class="videoTitle"
@click="play(id)"
>
{{ title }}
</p>
<p
class="channelName"
@click="goToChannel"
>
{{ channelName }}
</p>
<span
v-if="!isLive && !hideViews"
class="viewCount"
@click="play(id)"
>
{{ viewCount }} views
</span>
<span
v-if="uploadedTime !== '' && !isLive"
class="uploadedTime"
@click="play(id)"
>
- {{ uploadedTime }}
</span>
<span
v-if="isLive"
class="viewCount"
@click="play(id)"
>
{{ viewCount }} watching
</span>
<p
v-if="listType !== 'grid'"
class="description"
@click="play(id)"
>
{{ description }}
</p>
<span
v-if="isLive"
class="liveText"
@click="play(id)"
>
LIVE NOW
</span>
<div class="videoInfo">
<ft-icon-button
class="optionsButton"
title="More Options"
theme="base"
:size="16"
:use-shadow="false"
dropdown-position-x="left"
:dropdown-names="optionsNames"
:dropdown-values="optionsValues"
@click="handleOptionsClick"
/>
<router-link
class="title"
:to="{
path: `/watch/${id}`,
query: playlistId ? {playlistId} : {}
}"
>
{{ title }}
</router-link>
<div class="infoLine">
<router-link class="channelName" :to="`/channel/${channelId}`">{{ channelName }}</router-link>
<span v-if="!isLive && !hideViews" class="viewCount"> {{ viewCount }} views</span>
<span v-if="uploadedTime !== '' && !isLive" class="uploadedTime"> {{ uploadedTime }}</span>
<span v-if="isLive" class="viewCount"> {{ viewCount }} watching</span>
</div>
<p
v-if="listType !== 'grid' && appearance === 'result'"
class="description"
>
{{ description }}
</p>
</div>
</div>
</template>
<script src="./ft-list-video.js" />
<style scoped src="./ft-list-video.css" />
<style scoped src="./ft-list-video.sass" lang="sass" />

View File

@ -14,6 +14,7 @@
/>
<ft-list-video
v-if="result.type === 'video' || result.type === 'shortVideo'"
appearance="result"
:data="result"
/>
<ft-list-playlist
@ -35,6 +36,7 @@
/>
<ft-list-video
v-if="result.type === 'video' || result.type === 'shortVideo'"
appearance="result"
:data="result"
/>
<ft-list-playlist

View File

@ -37,36 +37,34 @@
.playlistItems {
overflow-y: auto;
height: 395px;
margin-top: -15px;
margin-left: -16px;
margin-right: -16px;
}
.playlistItem {
height: 75px;
width: 100%;
display: grid;
grid-template-columns: 30px 1fr;
align-items: center;
transition: background 0.2s ease-out;
}
.playlistItem:not(:last-child) {
margin-bottom: 8px;
}
.playlistItem:hover {
background-color: var(--side-nav-hover-color);
transition: background 0.2s ease-in;
}
.videoIndexContainer {
text-align: center;
}
.videoIndex {
float: left;
position: relative;
top: 15px;
left: 10px;
color: var(--tertiary-text-color);
}
.videoIndexIcon {
float: left;
position: relative;
font-size: 14px;
top: 32px;
left: 10px;
color: var(--tertiary-text-color);
}

View File

@ -56,22 +56,24 @@
:key="index"
class="playlistItem"
>
<font-awesome-icon
v-if="item.videoId === videoId"
class="videoIndexIcon"
icon="play"
/>
<p
v-else
class="videoIndex"
>
{{ index + 1 }}
</p>
<div class="videoIndexContainer">
<font-awesome-icon
v-if="item.videoId === videoId"
class="videoIndexIcon"
icon="play"
/>
<p
v-else
class="videoIndex"
>
{{ index + 1 }}
</p>
</div>
<ft-list-video
:data="item"
:playlist-id="playlistId"
appearance="watchPlaylistItem"
force-list-type="list"
class="videoInfo"
/>
</div>
</ft-flex-box>

View File

@ -1,7 +1,4 @@
.relative {
position: relative;
}
.videoRecommendation {
margin-bottom: -15px;
.watchVideoRecommendations {
display: grid;
grid-gap: 8px;
}

View File

@ -1,5 +1,5 @@
<template>
<ft-card class="relative">
<ft-card class="relative watchVideoRecommendations">
<h3>
Up Next
</h3>
@ -7,8 +7,8 @@
v-for="(video, index) in data"
:key="index"
:data="video"
appearance="recommendation"
force-list-type="list"
class="videoRecommendation"
/>
</ft-card>
</template>

View File

@ -0,0 +1,151 @@
$thumbnail-overlay-opacity: 0.85
@mixin is-result
@at-root
.result#{&}
@content
@mixin is-watch-playlist-item
@at-root
.watchPlaylistItem#{&}
@content
@mixin is-recommendation
@at-root
.recommendation#{&}
@content
@mixin is-sidebar-item
@at-root
.watchPlaylistItem#{&}, .recommendation#{&}
@content
.ft-list-video
.videoThumbnail
display: flex
position: relative
.thumbnailLink
display: flex
.thumbnailImage
height: 130px
@include is-sidebar-item
height: 75px
@include is-recommendation
width: 163px
height: auto
.videoDuration
position: absolute
bottom: 4px
right: 4px
padding: 3px 4px
line-height: 1.2
font-size: 15px
border-radius: 5px
margin: 0
opacity: $thumbnail-overlay-opacity
color: var(--primary-text-color)
background-color: var(--card-bg-color)
&.live
background-color: #f22
color: #fff
.favoritesIcon
position: absolute
top: 3px
right: 3px
font-size: 17px
opacity: $thumbnail-overlay-opacity
.videoCountContainer
position: absolute
right: 0
top: 0
bottom: 0
width: 60px
font-size: 20px
.background, .inner
position: absolute
top: 0
bottom: 0
left: 0
right: 0
.background
background-color: var(--bg-color)
opacity: 0.9
.inner
display: flex
flex-direction: column
justify-content: center
align-items: center
color: var(--primary-text-color)
.videoInfo
flex: 1
position: relative
.optionsButton
float: right // ohhhh man, float was finally the right choice for something
.title
font-size: 20px
color: var(--primary-text-color)
text-decoration: none
@include is-sidebar-item
font-size: 15px
.infoLine
margin-top: 5px
font-size: 14px
@include is-sidebar-item
font-size: 12px
&, .channelName
color: var(--secondary-text-color)
.description
font-size: 14px
color: var(--secondary-text-color)
&.list
display: flex
align-items: flex-start
.videoThumbnail
margin-right: 20px
@include is-sidebar-item
margin-right: 10px
&.grid
display: flex
flex-direction: column
min-height: 230px
padding-bottom: 20px
.videoThumbnail
margin-bottom: 12px
.thumbnailImage
width: 100%
.title
font-size: 18px
.infoLine
margin-top: 8px
font-size: 13px
.videoWatched, .live
text-transform: uppercase

View File

@ -12,4 +12,7 @@
.playlistItems {
float: right;
width: 60%;
padding: 10px;
display: grid;
grid-gap: 10px;
}

View File

@ -13,16 +13,14 @@
v-if="!isLoading"
class="playlistItems"
>
<ft-flex-box>
<ft-list-video
v-for="(item, index) in playlistItems"
:key="index"
:data="item"
:playlist-id="playlistId"
force-list-type="list"
class="playlistItem"
/>
</ft-flex-box>
<ft-list-video
v-for="(item, index) in playlistItems"
:key="index"
:data="item"
:playlist-id="playlistId"
appearance="result"
force-list-type="list"
/>
</ft-card>
</div>
</template>

View File

@ -50,8 +50,10 @@
min-width: 380px
.watchVideoPlaylist, .watchVideoSidebar, .theatrePlaylist
height: 500px
margin: 0 8px 16px
.watchVideoSidebar, .theatrePlaylist
height: 500px
.watchVideoRecommendations, .theatreRecommendations
margin: 0 8px 16px