Merge branch 'master' into ft-toast
|
@ -25,30 +25,75 @@ jobs:
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run build --if-present
|
- run: npm run build --if-present
|
||||||
- name: Upload .deb Artifact
|
- name: Build ARM64 with Node.js ${{ matrix.node-version}}
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
run: npm run build:arm --if-present
|
||||||
|
- name: Upload Linux .zip x64 Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_portable_x64.zip
|
||||||
|
path: build/freetube-vue-0.8.0.zip
|
||||||
|
- name: Upload Linux .zip ARM Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_portable_arm64.zip
|
||||||
|
path: build/freetube-vue-0.8.0-arm64.zip
|
||||||
|
- name: Upload .deb x64 Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
with:
|
with:
|
||||||
name: freetube-vue_0.8.0_amd64.deb
|
name: freetube-vue_0.8.0_amd64.deb
|
||||||
path: build/freetube-vue_0.8.0_amd64.deb
|
path: build/freetube-vue_0.8.0_amd64.deb
|
||||||
- name: Upload AppImage Artifact
|
- name: Upload .deb ARM Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_arm64.deb
|
||||||
|
path: build/freetube-vue_0.8.0_arm64.deb
|
||||||
|
- name: Upload AppImage x64 Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
with:
|
with:
|
||||||
name: freetube-vue_0.8.0_amd64.AppImage
|
name: freetube-vue_0.8.0_amd64.AppImage
|
||||||
path: build/FreeTube-Vue-0.8.0.AppImage
|
path: build/FreeTube-Vue-0.8.0.AppImage
|
||||||
- name: Upload .rpm Artifact
|
- name: Upload AppImage ARM Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_arm64.AppImage
|
||||||
|
path: build/FreeTube-Vue-0.8.0-arm64.AppImage
|
||||||
|
- name: Upload .rpm x64 Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
with:
|
with:
|
||||||
name: freetube-vue_0.8.0_amd64.rpm
|
name: freetube-vue_0.8.0_amd64.rpm
|
||||||
path: build/freetube-vue-0.8.0.x86_64.rpm
|
path: build/freetube-vue-0.8.0.x86_64.rpm
|
||||||
- name: Upload Linux .zip Artifact
|
- name: Upload .rpm ARM Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
with:
|
with:
|
||||||
name: freetube-vue_0.8.0_amd64.zip
|
name: freetube-vue_0.8.0_arm64.rpm
|
||||||
path: build/freetube-vue-0.8.0.zip
|
path: build/freetube-vue-0.8.0.arm64.rpm
|
||||||
|
- name: Upload Alpine .apk x64 Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_alpine_amd64.apk
|
||||||
|
path: build/freetube-vue-0.8.0.apk
|
||||||
|
- name: Upload Alpine .apk ARM Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_alpine_arm64.apk
|
||||||
|
path: build/freetube-vue-0.8.0-arm64.apk
|
||||||
|
- name: Upload Web Build
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
|
with:
|
||||||
|
name: freetube-vue_0.8.0_static_web
|
||||||
|
path: dist/web
|
||||||
- name: Upload Windows .exe Artifact
|
- name: Upload Windows .exe Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: startsWith(matrix.os, 'windows')
|
if: startsWith(matrix.os, 'windows')
|
||||||
|
@ -61,6 +106,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: freetube-vue-0.8.0-setup-x64.exe
|
name: freetube-vue-0.8.0-setup-x64.exe
|
||||||
path: build/FreeTube-Vue Setup 0.8.0.exe
|
path: build/FreeTube-Vue Setup 0.8.0.exe
|
||||||
|
- name: Upload Windows Portable Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: startsWith(matrix.os, 'windows')
|
||||||
|
with:
|
||||||
|
name: freetube-vue-0.8.0-portable-x64.exe
|
||||||
|
path: build/FreeTube-Vue 0.8.0.exe
|
||||||
- name: Upload Mac .dmg Artifact
|
- name: Upload Mac .dmg Artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
|
|
@ -7,6 +7,13 @@
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "dev",
|
"script": "dev",
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "dev-runner",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"label": "npm: dev-runner",
|
||||||
|
"detail": "node _scripts/dev-runner.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 526 B |
After Width: | Height: | Size: 785 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
|
@ -2,7 +2,9 @@ const os = require('os')
|
||||||
const builder = require('electron-builder')
|
const builder = require('electron-builder')
|
||||||
|
|
||||||
const Platform = builder.Platform
|
const Platform = builder.Platform
|
||||||
|
const Arch = builder.Arch
|
||||||
const { name, productName } = require('../package.json')
|
const { name, productName } = require('../package.json')
|
||||||
|
const args = process.argv
|
||||||
|
|
||||||
let targets
|
let targets
|
||||||
var platform = os.platform()
|
var platform = os.platform()
|
||||||
|
@ -12,7 +14,13 @@ if (platform == 'darwin') {
|
||||||
} else if (platform == 'win32') {
|
} else if (platform == 'win32') {
|
||||||
targets = Platform.WINDOWS.createTarget()
|
targets = Platform.WINDOWS.createTarget()
|
||||||
} else if (platform == 'linux') {
|
} else if (platform == 'linux') {
|
||||||
targets = Platform.LINUX.createTarget()
|
let arch = Arch.x64
|
||||||
|
|
||||||
|
if (args[2] === 'arm') {
|
||||||
|
arch = Arch.arm64
|
||||||
|
}
|
||||||
|
|
||||||
|
targets = Platform.LINUX.createTarget(['deb', 'zip', 'apk', 'rpm', 'AppImage'], arch)
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
@ -47,7 +55,7 @@ const config = {
|
||||||
linux: {
|
linux: {
|
||||||
category: 'Network',
|
category: 'Network',
|
||||||
icon: '_icons/icon.png',
|
icon: '_icons/icon.png',
|
||||||
target: ['deb', 'rpm', 'zip', 'AppImage'],
|
target: ['deb', 'zip', 'apk', 'rpm', 'AppImage'],
|
||||||
},
|
},
|
||||||
mac: {
|
mac: {
|
||||||
category: 'public.app-category.utilities',
|
category: 'public.app-category.utilities',
|
||||||
|
|
|
@ -85,6 +85,13 @@ if (isDevMode) {
|
||||||
ignore: ['.*'],
|
ignore: ['.*'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
from: path.join(__dirname, '../src/renderer/assets/img'),
|
||||||
|
to: path.join(__dirname, '../dist/images'),
|
||||||
|
globOptions: {
|
||||||
|
ignore: ['.*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
|
@ -132,6 +132,7 @@ const config = {
|
||||||
'@': path.join(__dirname, '../src/'),
|
'@': path.join(__dirname, '../src/'),
|
||||||
src: path.join(__dirname, '../src/'),
|
src: path.join(__dirname, '../src/'),
|
||||||
icons: path.join(__dirname, '../_icons/'),
|
icons: path.join(__dirname, '../_icons/'),
|
||||||
|
images: path.join(__dirname, '../src/renderer/assets/img/'),
|
||||||
},
|
},
|
||||||
extensions: ['.ts', '.js', '.vue', '.json'],
|
extensions: ['.ts', '.js', '.vue', '.json'],
|
||||||
},
|
},
|
||||||
|
@ -171,6 +172,13 @@ if (isDevMode) {
|
||||||
ignore: ['.*'],
|
ignore: ['.*'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
from: path.join(__dirname, '../src/renderer/assets/img'),
|
||||||
|
to: path.join(__dirname, '../dist/web/images'),
|
||||||
|
globOptions: {
|
||||||
|
ignore: ['.*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
|
@ -135,6 +135,7 @@ const config = {
|
||||||
vue$: 'vue/dist/vue.esm.js',
|
vue$: 'vue/dist/vue.esm.js',
|
||||||
src: path.join(__dirname, '../src/'),
|
src: path.join(__dirname, '../src/'),
|
||||||
icons: path.join(__dirname, '../_icons/'),
|
icons: path.join(__dirname, '../_icons/'),
|
||||||
|
images: path.join(__dirname, '../src/renderer/assets/img/'),
|
||||||
},
|
},
|
||||||
extensions: ['.js', '.vue', '.json', '.css'],
|
extensions: ['.js', '.vue', '.json', '.css'],
|
||||||
},
|
},
|
||||||
|
@ -174,6 +175,13 @@ if (isDevMode) {
|
||||||
ignore: ['.*'],
|
ignore: ['.*'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
from: path.join(__dirname, '../src/renderer/assets/img'),
|
||||||
|
to: path.join(__dirname, '../dist/web/images'),
|
||||||
|
globOptions: {
|
||||||
|
ignore: ['.*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
64
package.json
|
@ -8,14 +8,14 @@
|
||||||
"url": "https://github.com/FreeTubeApp/FreeTube/issues"
|
"url": "https://github.com/FreeTubeApp/FreeTube/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.29",
|
"@fortawesome/fontawesome-svg-core": "^1.2.30",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.13.1",
|
"@fortawesome/free-solid-svg-icons": "^5.14.0",
|
||||||
"@fortawesome/vue-fontawesome": "^0.1.10",
|
"@fortawesome/vue-fontawesome": "^0.1.10",
|
||||||
"@silvermine/videojs-quality-selector": "^1.2.4",
|
"@silvermine/videojs-quality-selector": "^1.2.4",
|
||||||
"autolinker": "^3.14.1",
|
"autolinker": "^3.14.1",
|
||||||
"bulma-pro": "^0.2.0",
|
"bulma-pro": "^0.2.0",
|
||||||
"dateformat": "^3.0.3",
|
"dateformat": "^3.0.3",
|
||||||
"electron-context-menu": "^2.0.1",
|
"electron-context-menu": "^2.2.0",
|
||||||
"jquery": "^3.5.1",
|
"jquery": "^3.5.1",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
|
@ -32,42 +32,42 @@
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-electron": "^1.0.6",
|
"vue-electron": "^1.0.6",
|
||||||
"vue-router": "^3.3.4",
|
"vue-router": "^3.3.4",
|
||||||
"vuex": "^3.4.0",
|
"vuex": "^3.5.1",
|
||||||
"xml2json": "^0.12.0",
|
"xml2json": "^0.12.0",
|
||||||
"youtube-chat": "^1.1.0",
|
"youtube-chat": "^1.1.0",
|
||||||
"youtube-comments-fetch": "^1.0.1",
|
"youtube-comments-fetch": "^1.0.1",
|
||||||
"youtube-comments-task": "^1.3.15",
|
"youtube-comments-task": "^1.3.15",
|
||||||
"youtube-suggest": "^1.1.0",
|
"youtube-suggest": "^1.1.0",
|
||||||
"yt-channel-info": "git+https://github.com/FreeTubeApp/yt-channel-info.git",
|
"yt-channel-info": "^1.0.1",
|
||||||
"yt-xml2vtt": "^1.1.1",
|
"yt-xml2vtt": "^1.1.1",
|
||||||
"ytdl-core": "^3.1.1",
|
"ytdl-core": "^3.2.0",
|
||||||
"ytpl": "^0.1.21",
|
"ytpl": "^0.2.3",
|
||||||
"ytsr": "^0.1.15"
|
"ytsr": "^0.1.20"
|
||||||
},
|
},
|
||||||
"description": "A private YouTube client",
|
"description": "A private YouTube client",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.10.3",
|
"@babel/core": "^7.10.5",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.10.3",
|
"@babel/plugin-proposal-object-rest-spread": "^7.10.4",
|
||||||
"@babel/preset-env": "^7.10.3",
|
"@babel/preset-env": "^7.10.4",
|
||||||
"@babel/preset-typescript": "^7.10.1",
|
"@babel/preset-typescript": "^7.10.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^3.3.0",
|
"@typescript-eslint/eslint-plugin": "^3.7.1",
|
||||||
"@typescript-eslint/parser": "^3.3.0",
|
"@typescript-eslint/parser": "^3.7.1",
|
||||||
"acorn": "^7.3.1",
|
"acorn": "^7.3.1",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"copy-webpack-plugin": "^6.0.2",
|
"copy-webpack-plugin": "^6.0.3",
|
||||||
"css-loader": "^3.6.0",
|
"css-loader": "^4.1.0",
|
||||||
"devtron": "^1.4.0",
|
"devtron": "^1.4.0",
|
||||||
"electron": "^9.0.4",
|
"electron": "^9.1.2",
|
||||||
"electron-builder": "^22.7.0",
|
"electron-builder": "^22.8.0",
|
||||||
"electron-builder-squirrel-windows": "^22.7.0",
|
"electron-builder-squirrel-windows": "^22.8.1",
|
||||||
"electron-debug": "^3.1.0",
|
"electron-debug": "^3.1.0",
|
||||||
"electron-rebuild": "^1.11.0",
|
"electron-rebuild": "^1.11.0",
|
||||||
"eslint": "^7.3.0",
|
"eslint": "^7.5.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
"eslint-config-standard": "^14.1.1",
|
"eslint-config-standard": "^14.1.1",
|
||||||
"eslint-plugin-import": "^2.21.2",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
|
@ -76,28 +76,28 @@
|
||||||
"fast-glob": "^3.2.4",
|
"fast-glob": "^3.2.4",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"jest": "^26.0.1",
|
"jest": "^26.1.0",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
"mini-css-extract-plugin": "^0.9.0",
|
||||||
"node-abi": "^2.18.0",
|
"node-abi": "^2.18.0",
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^1.0.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^2.0.5",
|
"prettier": "^2.0.5",
|
||||||
"sass": "^1.26.8",
|
"sass": "^1.26.10",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^9.0.2",
|
||||||
"style-loader": "^1.2.1",
|
"style-loader": "^1.2.1",
|
||||||
"tree-kill": "1.2.2",
|
"tree-kill": "1.2.2",
|
||||||
"typescript": "^3.9.5",
|
"typescript": "^3.9.7",
|
||||||
"url-loader": "^4.1.0",
|
"url-loader": "^4.1.0",
|
||||||
"vue-devtools": "^5.1.3",
|
"vue-devtools": "^5.1.4",
|
||||||
"vue-eslint-parser": "^7.1.0",
|
"vue-eslint-parser": "^7.1.0",
|
||||||
"vue-loader": "^15.9.2",
|
"vue-loader": "^15.9.3",
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.2",
|
||||||
"vue-template-compiler": "^2.6.11",
|
"vue-template-compiler": "^2.6.11",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.44.0",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.0"
|
||||||
},
|
},
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"main": "./dist/main.js",
|
"main": "./dist/main.js",
|
||||||
"name": "freetube-vue",
|
"name": "freetube-vue",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -108,7 +108,9 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "run-s rebuild:electron pack build-release",
|
"build": "run-s rebuild:electron pack build-release",
|
||||||
|
"build:arm": "run-s rebuild:electron pack build-release:arm",
|
||||||
"build-release": "node _scripts/build.js",
|
"build-release": "node _scripts/build.js",
|
||||||
|
"build-release:arm": "node _scripts/build.js arm",
|
||||||
"debug": "run-s rebuild:electron debug-runner",
|
"debug": "run-s rebuild:electron debug-runner",
|
||||||
"debug-runner": "node _scripts/dev-runner.js --remote-debug",
|
"debug-runner": "node _scripts/dev-runner.js --remote-debug",
|
||||||
"dev": "run-s rebuild:electron dev-runner",
|
"dev": "run-s rebuild:electron dev-runner",
|
||||||
|
|
|
@ -64,6 +64,7 @@ function createWindow () {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
width: 960,
|
width: 960,
|
||||||
height: 540,
|
height: 540,
|
||||||
|
autoHideMenuBar: true,
|
||||||
// useContentSize: true,
|
// useContentSize: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
|
|
After Width: | Height: | Size: 7.8 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
name: 'FtAutoGrid',
|
||||||
|
props: {
|
||||||
|
grid: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -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
|
|
@ -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" />
|
|
@ -1,6 +1,6 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.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 FtListVideo from '../ft-list-video/ft-list-video.vue'
|
||||||
import FtListChannel from '../ft-list-channel/ft-list-channel.vue'
|
import FtListChannel from '../ft-list-channel/ft-list-channel.vue'
|
||||||
import FtListPlaylist from '../ft-list-playlist/ft-list-playlist.vue'
|
import FtListPlaylist from '../ft-list-playlist/ft-list-playlist.vue'
|
||||||
|
@ -9,7 +9,7 @@ export default Vue.extend({
|
||||||
name: 'FtElementList',
|
name: 'FtElementList',
|
||||||
components: {
|
components: {
|
||||||
'ft-flex-box': FtFlexBox,
|
'ft-flex-box': FtFlexBox,
|
||||||
'ft-grid': FtGrid,
|
'ft-auto-grid': FtAutoGrid,
|
||||||
'ft-list-video': FtListVideo,
|
'ft-list-video': FtListVideo,
|
||||||
'ft-list-channel': FtListChannel,
|
'ft-list-channel': FtListChannel,
|
||||||
'ft-list-playlist': FtListPlaylist
|
'ft-list-playlist': FtListPlaylist
|
||||||
|
|
|
@ -1,49 +1,30 @@
|
||||||
<template>
|
<template>
|
||||||
<span>
|
<ft-auto-grid
|
||||||
<ft-flex-box
|
:grid="listType !== 'list'"
|
||||||
v-if="listType === 'list'"
|
|
||||||
>
|
>
|
||||||
<span
|
<template
|
||||||
v-for="(result, index) in data"
|
v-for="(result, index) in data"
|
||||||
:key="index"
|
|
||||||
class="maxWidth"
|
|
||||||
>
|
>
|
||||||
<ft-list-channel
|
<ft-list-channel
|
||||||
v-if="result.type === 'channel'"
|
v-if="result.type === 'channel'"
|
||||||
|
:key="index"
|
||||||
|
appearance="result"
|
||||||
:data="result"
|
:data="result"
|
||||||
/>
|
/>
|
||||||
<ft-list-video
|
<ft-list-video
|
||||||
v-if="result.type === 'video' || result.type === 'shortVideo'"
|
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"
|
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
appearance="result"
|
||||||
<ft-list-channel
|
|
||||||
v-if="result.type === 'channel'"
|
|
||||||
:data="result"
|
|
||||||
/>
|
|
||||||
<ft-list-video
|
|
||||||
v-if="result.type === 'video' || result.type === 'shortVideo'"
|
|
||||||
:data="result"
|
:data="result"
|
||||||
/>
|
/>
|
||||||
<ft-list-playlist
|
<ft-list-playlist
|
||||||
v-if="result.type === 'playlist'"
|
v-if="result.type === 'playlist'"
|
||||||
|
:key="index"
|
||||||
|
appearance="result"
|
||||||
:data="result"
|
:data="result"
|
||||||
/>
|
/>
|
||||||
</span>
|
</template>
|
||||||
</ft-grid>
|
</ft-auto-grid>
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-element-list.js" />
|
<script src="./ft-element-list.js" />
|
||||||
|
|
|
@ -19,6 +19,14 @@ export default Vue.extend({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
padding: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
forceDropdown: {
|
forceDropdown: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
flex-flow: row wrap
|
flex-flow: row wrap
|
||||||
justify-content: space-evenly
|
justify-content: space-evenly
|
||||||
position: relative
|
position: relative
|
||||||
|
user-select: none
|
||||||
|
|
||||||
.iconButton
|
.iconButton
|
||||||
width: 1em
|
width: 1em
|
||||||
height: 1em
|
height: 1em
|
||||||
padding: 10px
|
|
||||||
font-size: 20px
|
|
||||||
border-radius: 50%
|
border-radius: 50%
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
transition: background 0.15s ease-out
|
transition: background 0.15s ease-out
|
||||||
|
@ -59,10 +58,10 @@
|
||||||
user-select: none
|
user-select: none
|
||||||
|
|
||||||
&.left
|
&.left
|
||||||
right: calc(50% - 20px)
|
right: calc(50% - 10px)
|
||||||
|
|
||||||
&.right
|
&.right
|
||||||
left: calc(50% - 20px)
|
left: calc(50% - 10px)
|
||||||
|
|
||||||
.list
|
.list
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
secondary: theme === 'secondary',
|
secondary: theme === 'secondary',
|
||||||
shadow: useShadow
|
shadow: useShadow
|
||||||
}"
|
}"
|
||||||
|
:style="{
|
||||||
|
padding: padding + 'px',
|
||||||
|
fontSize: size + 'px'
|
||||||
|
}"
|
||||||
@click="handleIconClick"
|
@click="handleIconClick"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
.channelThumbnail {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelThumbnail img {
|
|
||||||
width: 140px;
|
|
||||||
height: 140px;
|
|
||||||
border-radius: 200px 200px 200px 200px;
|
|
||||||
-webkit-border-radius: 200px 200px 200px 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelName {
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--title-color);
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subscriberCount {
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoCount {
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
width: 240px;
|
|
||||||
height: 250px;
|
|
||||||
padding: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .channelThumbnail {
|
|
||||||
width: 100%;
|
|
||||||
height: 140px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .channelThumbnail img {
|
|
||||||
position: relative;
|
|
||||||
left: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid .channelName {
|
|
||||||
width: 240px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list {
|
|
||||||
height: 140px;
|
|
||||||
width: 100%;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-top: 15px;
|
|
||||||
border-bottom: 1px solid var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list .channelThumbnail {
|
|
||||||
float: left;
|
|
||||||
width: 240px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list .channelThumbnail img {
|
|
||||||
position: relative;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
left: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list .channelName {
|
|
||||||
margin-left: 250px;
|
|
||||||
width: 275px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list .subscriberCount {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list .videoCount {
|
|
||||||
margin-left: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list .description {
|
|
||||||
margin-left: 250px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
height: 35px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
|
@ -6,6 +6,10 @@ export default Vue.extend({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
appearance: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
|
@ -32,10 +36,6 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goToChannel: function () {
|
|
||||||
this.$router.push({ path: `/channel/${this.id}` })
|
|
||||||
},
|
|
||||||
|
|
||||||
parseLocalData: function () {
|
parseLocalData: function () {
|
||||||
this.thumbnail = this.data.avatar
|
this.thumbnail = this.data.avatar
|
||||||
this.channelName = this.data.name
|
this.channelName = this.data.name
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
@use "../../sass-partials/_ft-list-item"
|
|
@ -1,32 +1,41 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="ft-list-channel"
|
class="ft-list-channel ft-list-item"
|
||||||
:class="{ list: listType === 'list', grid: listType === 'grid' }"
|
:class="{
|
||||||
|
list: listType === 'list',
|
||||||
|
grid: listType === 'grid',
|
||||||
|
[appearance]: true
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<div class="channelThumbnail">
|
<div class="channelThumbnail">
|
||||||
|
<router-link
|
||||||
|
:to="`/channel/${id}`"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="thumbnail"
|
:src="thumbnail"
|
||||||
@click="goToChannel(id)"
|
class="channelImage"
|
||||||
>
|
>
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<div class="info">
|
||||||
class="channelName"
|
<router-link
|
||||||
@click="goToChannel(id)"
|
class="title"
|
||||||
|
:to="`/channel/${id}`"
|
||||||
>
|
>
|
||||||
{{ channelName }}
|
{{ channelName }}
|
||||||
</p>
|
</router-link>
|
||||||
|
<div class="infoLine">
|
||||||
<span
|
<span
|
||||||
class="subscriberCount"
|
class="subscriberCount"
|
||||||
@click="goToChannel(id)"
|
|
||||||
>
|
>
|
||||||
{{ subscriberCount }} subscribers
|
{{ subscriberCount }} subscribers
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="videoCount"
|
class="videoCount"
|
||||||
@click="goToChannel(id)"
|
|
||||||
>
|
>
|
||||||
- {{ videoCount }} videos
|
- {{ videoCount }} videos
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="listType !== 'grid'"
|
v-if="listType !== 'grid'"
|
||||||
class="description"
|
class="description"
|
||||||
|
@ -34,7 +43,8 @@
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-list-channel.js" />
|
<script src="./ft-list-channel.js" />
|
||||||
<style scoped src="./ft-list-channel.css" />
|
<style scoped lang="sass" src="./ft-list-channel.sass" />
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -6,6 +6,10 @@ export default Vue.extend({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
appearance: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
|
@ -58,14 +62,6 @@ export default Vue.extend({
|
||||||
this.channelLink = this.data.author.ref
|
this.channelLink = this.data.author.ref
|
||||||
this.playlistLink = this.data.link
|
this.playlistLink = this.data.link
|
||||||
this.videoCount = parseInt(this.data.length.split(' ')[0])
|
this.videoCount = parseInt(this.data.length.split(' ')[0])
|
||||||
},
|
|
||||||
|
|
||||||
goToPlaylist: function (id) {
|
|
||||||
this.$router.push({ path: `/playlist/${id}` })
|
|
||||||
},
|
|
||||||
|
|
||||||
goToChannel: function (id) {
|
|
||||||
console.log(id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
@use "../../sass-partials/_ft-list-item"
|
|
@ -1,38 +1,45 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="ft-list-video"
|
class="ft-list-video ft-list-item"
|
||||||
|
:appearance="appearance"
|
||||||
:class="{ list: listType === 'list', grid: listType === 'grid' }"
|
:class="{ list: listType === 'list', grid: listType === 'grid' }"
|
||||||
>
|
>
|
||||||
<div class="videoThumbnail">
|
<router-link
|
||||||
|
class="videoThumbnail"
|
||||||
|
:to="`/playlist/${playlistId}`"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="thumbnail"
|
:src="thumbnail"
|
||||||
@click="goToPlaylist(playlistId)"
|
class="thumbnailImage"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="videoCountContainer"
|
class="videoCountContainer"
|
||||||
@click="goToPlaylist(playlistId)"
|
|
||||||
>
|
>
|
||||||
<span>
|
<div class="background" />
|
||||||
{{ videoCount }}
|
<div class="inner">
|
||||||
<br>
|
<div>{{ videoCount }}</div>
|
||||||
<font-awesome-icon icon="list" />
|
<div><font-awesome-icon icon="list" /></div>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p
|
</router-link>
|
||||||
class="playlistTitle"
|
<div class="info">
|
||||||
@click="goToPlaylist(playlistId)"
|
<router-link
|
||||||
|
class="title"
|
||||||
|
:to="`/playlist/${playlistId}`"
|
||||||
>
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</p>
|
</router-link>
|
||||||
<p
|
<div class="infoLine">
|
||||||
|
<router-link
|
||||||
class="channelName"
|
class="channelName"
|
||||||
@click="goToChannel(channelId)"
|
:to="`/channel/${channelId}`"
|
||||||
>
|
>
|
||||||
{{ channelName }}
|
{{ channelName }}
|
||||||
</p>
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-list-playlist.js" />
|
<script src="./ft-list-playlist.js" />
|
||||||
<style scoped src="./ft-list-playlist.css" />
|
<style scoped lang="sass" src="./ft-list-playlist.sass" />
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -18,6 +18,10 @@ export default Vue.extend({
|
||||||
forceListType: {
|
forceListType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
|
},
|
||||||
|
appearance: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
|
@ -121,31 +125,6 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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 () {
|
toggleSave: function () {
|
||||||
console.log('TODO: ft-list-video method toggleSave')
|
console.log('TODO: ft-list-video method toggleSave')
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
@use "../../sass-partials/_ft-list-item"
|
|
@ -1,27 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="ft-list-video"
|
class="ft-list-video ft-list-item"
|
||||||
:class="{
|
:class="{
|
||||||
list: (listType === 'list' || forceListType === 'list') && forceListType !== 'grid',
|
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"
|
||||||
|
>
|
||||||
|
<router-link
|
||||||
|
class="thumbnailLink"
|
||||||
|
:to="{
|
||||||
|
path: `/watch/${id}`,
|
||||||
|
query: playlistId ? {playlistId} : {}
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="videoThumbnail">
|
|
||||||
<img
|
<img
|
||||||
:src="thumbnail"
|
:src="thumbnail"
|
||||||
@click="play(id)"
|
class="thumbnailImage"
|
||||||
>
|
>
|
||||||
<p
|
</router-link>
|
||||||
v-if="!isLive"
|
<div
|
||||||
class="videoDuration"
|
class="videoDuration"
|
||||||
@click="play(id)"
|
:class="{ live: isLive }"
|
||||||
>
|
>
|
||||||
{{ duration }}
|
{{ isLive ? "Live" : duration }}
|
||||||
</p>
|
</div>
|
||||||
<font-awesome-icon
|
<ft-icon-button
|
||||||
v-if="!isLive"
|
v-if="!isLive"
|
||||||
icon="star"
|
icon="star"
|
||||||
class="favoritesIcon"
|
class="favoritesIcon"
|
||||||
|
:padding="appearance === `watchPlaylistItem` ? 5 : 6"
|
||||||
|
:size="appearance === `watchPlaylistItem` ? 14 : 18"
|
||||||
:class="{ favorited: isFavorited }"
|
:class="{ favorited: isFavorited }"
|
||||||
@click="toggleSave(id)"
|
@click="toggleSave(id)"
|
||||||
/>
|
/>
|
||||||
|
@ -29,7 +41,7 @@
|
||||||
v-if="watched"
|
v-if="watched"
|
||||||
class="videoWatched"
|
class="videoWatched"
|
||||||
>
|
>
|
||||||
WATCHED
|
Watched
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="watched"
|
v-if="watched"
|
||||||
|
@ -37,65 +49,56 @@
|
||||||
:style="{width: progressPercentage + '%'}"
|
:style="{width: progressPercentage + '%'}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="info">
|
||||||
<ft-icon-button
|
<ft-icon-button
|
||||||
class="optionsButton"
|
class="optionsButton"
|
||||||
title="More Options"
|
title="More Options"
|
||||||
theme="base"
|
theme="base"
|
||||||
|
:size="16"
|
||||||
:use-shadow="false"
|
:use-shadow="false"
|
||||||
dropdown-position-x="left"
|
dropdown-position-x="left"
|
||||||
:dropdown-names="optionsNames"
|
:dropdown-names="optionsNames"
|
||||||
:dropdown-values="optionsValues"
|
:dropdown-values="optionsValues"
|
||||||
@click="handleOptionsClick"
|
@click="handleOptionsClick"
|
||||||
/>
|
/>
|
||||||
<p
|
<router-link
|
||||||
class="videoTitle"
|
class="title"
|
||||||
@click="play(id)"
|
:to="{
|
||||||
|
path: `/watch/${id}`,
|
||||||
|
query: playlistId ? {playlistId} : {}
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</p>
|
</router-link>
|
||||||
<p
|
<div class="infoLine">
|
||||||
|
<router-link
|
||||||
class="channelName"
|
class="channelName"
|
||||||
@click="goToChannel"
|
:to="`/channel/${channelId}`"
|
||||||
>
|
>
|
||||||
{{ channelName }}
|
<span>{{ channelName }}</span>
|
||||||
</p>
|
</router-link>
|
||||||
<span
|
<span
|
||||||
v-if="!isLive && !hideViews"
|
v-if="!isLive && !hideViews"
|
||||||
class="viewCount"
|
class="viewCount"
|
||||||
@click="play(id)"
|
>• {{ viewCount }} views</span>
|
||||||
>
|
|
||||||
{{ viewCount }} views
|
|
||||||
</span>
|
|
||||||
<span
|
<span
|
||||||
v-if="uploadedTime !== '' && !isLive"
|
v-if="uploadedTime !== '' && !isLive"
|
||||||
class="uploadedTime"
|
class="uploadedTime"
|
||||||
@click="play(id)"
|
>• {{ uploadedTime }}</span>
|
||||||
>
|
|
||||||
- {{ uploadedTime }}
|
|
||||||
</span>
|
|
||||||
<span
|
<span
|
||||||
v-if="isLive"
|
v-if="isLive"
|
||||||
class="viewCount"
|
class="viewCount"
|
||||||
@click="play(id)"
|
>• {{ viewCount }} watching</span>
|
||||||
>
|
</div>
|
||||||
{{ viewCount }} watching
|
|
||||||
</span>
|
|
||||||
<p
|
<p
|
||||||
v-if="listType !== 'grid'"
|
v-if="listType !== 'grid' && appearance === 'result'"
|
||||||
class="description"
|
class="description"
|
||||||
@click="play(id)"
|
|
||||||
>
|
>
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</p>
|
</p>
|
||||||
<span
|
</div>
|
||||||
v-if="isLive"
|
|
||||||
class="liveText"
|
|
||||||
@click="play(id)"
|
|
||||||
>
|
|
||||||
LIVE NOW
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-list-video.js" />
|
<script src="./ft-list-video.js" />
|
||||||
<style scoped src="./ft-list-video.css" />
|
<style scoped src="./ft-list-video.sass" lang="sass" />
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
.maxWidth {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
import Vue from 'vue'
|
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
|
||||||
import FtGrid from '../ft-grid/ft-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'
|
|
||||||
|
|
||||||
export default Vue.extend({
|
|
||||||
name: 'WatchPlaylist',
|
|
||||||
components: {
|
|
||||||
'ft-flex-box': FtFlexBox,
|
|
||||||
'ft-grid': FtGrid,
|
|
||||||
'ft-list-video': FtListVideo,
|
|
||||||
'ft-list-channel': FtListChannel,
|
|
||||||
'ft-list-playlist': FtListPlaylist
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
data: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
test: 'hello'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
listType: function () {
|
|
||||||
return this.$store.getters.getListType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -1,50 +0,0 @@
|
||||||
<template>
|
|
||||||
<span>
|
|
||||||
<ft-flex-box
|
|
||||||
v-if="listType === 'list'"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
v-for="(result, index) in data"
|
|
||||||
: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"
|
|
||||||
: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>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./watch-playlist.js" />
|
|
||||||
<style scoped src="./watch-playlist.css" />
|
|
|
@ -37,36 +37,34 @@
|
||||||
.playlistItems {
|
.playlistItems {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 395px;
|
height: 395px;
|
||||||
margin-top: -15px;
|
|
||||||
margin-left: -16px;
|
|
||||||
margin-right: -16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.playlistItem {
|
.playlistItem {
|
||||||
height: 75px;
|
display: grid;
|
||||||
width: 100%;
|
grid-template-columns: 30px 1fr;
|
||||||
|
align-items: center;
|
||||||
transition: background 0.2s ease-out;
|
transition: background 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.playlistItem:not(:last-child) {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.playlistItem:hover {
|
.playlistItem:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.videoIndexContainer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.videoIndex {
|
.videoIndex {
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
top: 15px;
|
|
||||||
left: 10px;
|
|
||||||
color: var(--tertiary-text-color);
|
color: var(--tertiary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.videoIndexIcon {
|
.videoIndexIcon {
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
top: 32px;
|
|
||||||
left: 10px;
|
|
||||||
color: var(--tertiary-text-color);
|
color: var(--tertiary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
@click="playNextVideo"
|
@click="playNextVideo"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<ft-flex-box
|
<div
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
class="playlistItems"
|
class="playlistItems"
|
||||||
>
|
>
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
:key="index"
|
:key="index"
|
||||||
class="playlistItem"
|
class="playlistItem"
|
||||||
>
|
>
|
||||||
|
<div class="videoIndexContainer">
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
v-if="item.videoId === videoId"
|
v-if="item.videoId === videoId"
|
||||||
class="videoIndexIcon"
|
class="videoIndexIcon"
|
||||||
|
@ -67,14 +68,15 @@
|
||||||
>
|
>
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
<ft-list-video
|
<ft-list-video
|
||||||
:data="item"
|
:data="item"
|
||||||
:playlist-id="playlistId"
|
:playlist-id="playlistId"
|
||||||
|
appearance="watchPlaylistItem"
|
||||||
force-list-type="list"
|
force-list-type="list"
|
||||||
class="videoInfo"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ft-flex-box>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ft-card>
|
</ft-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
.relative {
|
.watchVideoRecommendations {
|
||||||
position: relative;
|
display: grid;
|
||||||
}
|
grid-gap: 8px;
|
||||||
|
|
||||||
.videoRecommendation {
|
|
||||||
margin-bottom: -15px;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ft-card class="relative">
|
<ft-card class="relative watchVideoRecommendations">
|
||||||
<h3>
|
<h3>
|
||||||
Up Next
|
Up Next
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -7,8 +7,8 @@
|
||||||
v-for="(video, index) in data"
|
v-for="(video, index) in data"
|
||||||
:key="index"
|
:key="index"
|
||||||
:data="video"
|
:data="video"
|
||||||
|
appearance="recommendation"
|
||||||
force-list-type="list"
|
force-list-type="list"
|
||||||
class="videoRecommendation"
|
|
||||||
/>
|
/>
|
||||||
</ft-card>
|
</ft-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
$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-item
|
||||||
|
.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)
|
||||||
|
pointer-events: none
|
||||||
|
|
||||||
|
&.live
|
||||||
|
background-color: #f22
|
||||||
|
color: #fff
|
||||||
|
|
||||||
|
@include is-watch-playlist-item
|
||||||
|
font-size: 12px
|
||||||
|
|
||||||
|
.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)
|
||||||
|
|
||||||
|
.channelThumbnail
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
|
||||||
|
.channelImage
|
||||||
|
height: 130px
|
||||||
|
border-radius: 50%
|
||||||
|
|
||||||
|
.info
|
||||||
|
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, .channelThumbnail
|
||||||
|
margin-right: 20px
|
||||||
|
|
||||||
|
.channelThumbnail
|
||||||
|
width: 231px
|
||||||
|
|
||||||
|
@include is-sidebar-item
|
||||||
|
.videoThumbnail
|
||||||
|
margin-right: 10px
|
||||||
|
|
||||||
|
&.grid
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
min-height: 230px
|
||||||
|
padding-bottom: 20px
|
||||||
|
|
||||||
|
.videoThumbnail, .channelThumbnail
|
||||||
|
margin-bottom: 12px
|
||||||
|
|
||||||
|
.thumbnailImage
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
.title
|
||||||
|
font-size: 18px
|
||||||
|
|
||||||
|
.infoLine
|
||||||
|
margin-top: 8px
|
||||||
|
font-size: 13px
|
||||||
|
|
||||||
|
.videoWatched, .live
|
||||||
|
text-transform: uppercase
|
|
@ -10,6 +10,8 @@
|
||||||
--link-visited-color: var(--accent-color-visited);
|
--link-visited-color: var(--accent-color-visited);
|
||||||
--card-bg-color: #FFFFFF;
|
--card-bg-color: #FFFFFF;
|
||||||
--secondary-card-bg-color: #eeeeee;
|
--secondary-card-bg-color: #eeeeee;
|
||||||
|
--scrollbar-color: #CCCCCC;
|
||||||
|
--scrollbar-color-hover: #BDBDBD;
|
||||||
--side-nav-color: #FFFFFF;
|
--side-nav-color: #FFFFFF;
|
||||||
--side-nav-hover-color: #e0e0e0;
|
--side-nav-hover-color: #e0e0e0;
|
||||||
--side-nav-active-color: #757575;
|
--side-nav-active-color: #757575;
|
||||||
|
@ -32,6 +34,8 @@
|
||||||
--link-visited-color: var(--accent-color-visited);
|
--link-visited-color: var(--accent-color-visited);
|
||||||
--card-bg-color: #303030;
|
--card-bg-color: #303030;
|
||||||
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
||||||
|
--scrollbar-color: #414141;
|
||||||
|
--scrollbar-color-hover: #757575;
|
||||||
--side-nav-color: #262626;
|
--side-nav-color: #262626;
|
||||||
--side-nav-hover-color: #212121;
|
--side-nav-hover-color: #212121;
|
||||||
--side-nav-active-color: #303030;
|
--side-nav-active-color: #303030;
|
||||||
|
@ -53,6 +57,8 @@
|
||||||
--link-visited-color: var(--accent-color-visited);
|
--link-visited-color: var(--accent-color-visited);
|
||||||
--card-bg-color: #000000;
|
--card-bg-color: #000000;
|
||||||
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
|
||||||
|
--scrollbar-color: #515151;
|
||||||
|
--scrollbar-color-hover: #424242;
|
||||||
--side-nav-color: #000000;
|
--side-nav-color: #000000;
|
||||||
--side-nav-hover-color: #212121;
|
--side-nav-hover-color: #212121;
|
||||||
--side-nav-active-color: #303030;
|
--side-nav-active-color: #303030;
|
||||||
|
@ -442,9 +448,24 @@ body {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
color: var(--link-color);
|
color: var(--link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited {
|
a:visited {
|
||||||
color: var(--link-visited-color);
|
color: var(--link-visited-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scrollbar-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--scrollbar-color-hover);
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,16 @@
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.defaultChannelBanner {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
height: 200px;
|
||||||
|
background-color: black;
|
||||||
|
background-image: url("~images/defaultBanner.png");
|
||||||
|
}
|
||||||
|
|
||||||
.channelInfoContainer {
|
.channelInfoContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
|
@ -116,6 +126,10 @@
|
||||||
margin-top: 200px;
|
margin-top: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
color: var(--tertiary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
.getNextPage {
|
.getNextPage {
|
||||||
background-color: var(--search-bar-color);
|
background-color: var(--search-bar-color);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -123,4 +137,5 @@
|
||||||
line-height: 45px;
|
line-height: 45px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,28 @@ export default Vue.extend({
|
||||||
|
|
||||||
formattedSubCount: function () {
|
formattedSubCount: function () {
|
||||||
return this.subCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
return this.subCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||||
|
},
|
||||||
|
|
||||||
|
showFetchMoreButton: function () {
|
||||||
|
switch (this.currentTab) {
|
||||||
|
case 'videos':
|
||||||
|
if (this.videoContinuationString !== '' && this.videoContinuationString !== null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'playlists':
|
||||||
|
if (this.playlistContinuationString !== '' && this.playlistContinuationString !== null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'search':
|
||||||
|
if (this.searchContinuationString !== '' && this.searchContinuationString !== null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -132,13 +154,11 @@ export default Vue.extend({
|
||||||
} else {
|
} else {
|
||||||
switch (this.backendPreference) {
|
switch (this.backendPreference) {
|
||||||
case 'local':
|
case 'local':
|
||||||
this.apiUsed = 'local'
|
|
||||||
this.getChannelInfoLocal()
|
this.getChannelInfoLocal()
|
||||||
this.getChannelVideosLocal()
|
this.getChannelVideosLocal()
|
||||||
this.getPlaylistsLocal()
|
this.getPlaylistsLocal()
|
||||||
break
|
break
|
||||||
case 'invidious':
|
case 'invidious':
|
||||||
this.apiUsed = 'invidious'
|
|
||||||
this.getChannelInfoInvidious()
|
this.getChannelInfoInvidious()
|
||||||
this.getPlaylistsInvidious()
|
this.getPlaylistsInvidious()
|
||||||
break
|
break
|
||||||
|
@ -147,17 +167,37 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getChannelInfoLocal: function () {
|
getChannelInfoLocal: function () {
|
||||||
|
this.apiUsed = 'local'
|
||||||
ytch.getChannelInfo(this.id).then((response) => {
|
ytch.getChannelInfo(this.id).then((response) => {
|
||||||
this.id = response.authorId
|
this.id = response.authorId
|
||||||
this.channelName = response.author
|
this.channelName = response.author
|
||||||
this.subCount = response.subscriberCount
|
this.subCount = response.subscriberCount
|
||||||
this.thumbnailUrl = response.authorThumbnails[2].url
|
this.thumbnailUrl = response.authorThumbnails[2].url
|
||||||
this.bannerUrl = `https://${response.authorBanners[response.authorBanners.length - 1].url}`
|
|
||||||
this.channelDescription = response.description
|
this.channelDescription = response.description
|
||||||
this.relatedChannels = response.relatedChannels
|
this.relatedChannels = response.relatedChannels
|
||||||
|
|
||||||
|
if (response.authorBanners !== null) {
|
||||||
|
const bannerUrl = response.authorBanners[response.authorBanners.length - 1].url
|
||||||
|
|
||||||
|
if (!bannerUrl.includes('https')) {
|
||||||
|
this.bannerUrl = `https://${bannerUrl}`
|
||||||
|
} else {
|
||||||
|
this.bannerUrl = bannerUrl
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.bannerUrl = null
|
||||||
|
}
|
||||||
|
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
if (this.backendPreference === 'local' && this.backendFallback) {
|
||||||
|
console.log('Falling back to Invidious API')
|
||||||
|
this.getChannelInfoInvidious()
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
// TODO: Show toast with error message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -167,20 +207,30 @@ export default Vue.extend({
|
||||||
this.latestVideos = response.items
|
this.latestVideos = response.items
|
||||||
this.videoContinuationString = response.continuation
|
this.videoContinuationString = response.continuation
|
||||||
this.isElementListLoading = false
|
this.isElementListLoading = false
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
if (this.backendPreference === 'local' && this.backendFallback) {
|
||||||
|
console.log('Falling back to Invidious API')
|
||||||
|
this.getChannelInfoInvidious()
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
// TODO: Show toast with error message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
channelLocalNextPage: function () {
|
channelLocalNextPage: function () {
|
||||||
console.log(this.videoContinuationString)
|
ytch.getChannelVideosMore(this.videoContinuationString).then((response) => {
|
||||||
ytch.getChannelVideosMore(this.id, this.videoContinuationString).then((response) => {
|
|
||||||
this.latestVideos = this.latestVideos.concat(response.items)
|
this.latestVideos = this.latestVideos.concat(response.items)
|
||||||
this.videoContinuationString = response.continuation
|
this.videoContinuationString = response.continuation
|
||||||
console.log(this.videoContinuationString)
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
getChannelInfoInvidious: function () {
|
getChannelInfoInvidious: function () {
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
|
this.apiUsed = 'invidious'
|
||||||
|
|
||||||
this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => {
|
this.$store.dispatch('invidiousGetChannelInfo', this.id).then((response) => {
|
||||||
console.log(response)
|
console.log(response)
|
||||||
|
@ -188,10 +238,14 @@ export default Vue.extend({
|
||||||
this.id = response.authorId
|
this.id = response.authorId
|
||||||
this.subCount = response.subCount
|
this.subCount = response.subCount
|
||||||
this.thumbnailUrl = response.authorThumbnails[3].url
|
this.thumbnailUrl = response.authorThumbnails[3].url
|
||||||
this.bannerUrl = response.authorBanners[0].url
|
|
||||||
this.channelDescription = response.description
|
this.channelDescription = response.description
|
||||||
this.relatedChannels = response.relatedChannels
|
this.relatedChannels = response.relatedChannels
|
||||||
this.latestVideos = response.latestVideos
|
this.latestVideos = response.latestVideos
|
||||||
|
|
||||||
|
if (typeof (response.authorBanners) !== 'undefined') {
|
||||||
|
this.bannerUrl = response.authorBanners[0].url
|
||||||
|
}
|
||||||
|
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
|
@ -222,14 +276,25 @@ export default Vue.extend({
|
||||||
this.latestPlaylists = response.items
|
this.latestPlaylists = response.items
|
||||||
this.playlistContinuationString = response.continuation
|
this.playlistContinuationString = response.continuation
|
||||||
this.isElementListLoading = false
|
this.isElementListLoading = false
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
if (this.backendPreference === 'local' && this.backendFallback) {
|
||||||
|
console.log('Falling back to Invidious API')
|
||||||
|
this.getPlaylistsInvidious()
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
// TODO: Show toast with error message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
getPlaylistsLocalMore: function () {
|
getPlaylistsLocalMore: function () {
|
||||||
ytch.getChannelPlaylistsMore(this.id, this.playlistContinuationString).then((response) => {
|
ytch.getChannelPlaylistsMore(this.playlistContinuationString).then((response) => {
|
||||||
console.log(response)
|
console.log(response)
|
||||||
this.latestPlaylists = this.latestPlaylists.concat(response.items)
|
this.latestPlaylists = this.latestPlaylists.concat(response.items)
|
||||||
this.playlistContinuationString = response.continuation
|
this.playlistContinuationString = response.continuation
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -252,8 +317,15 @@ export default Vue.extend({
|
||||||
this.playlistContinuationString = response.continuation
|
this.playlistContinuationString = response.continuation
|
||||||
this.latestPlaylists = this.latestPlaylists.concat(response.playlists)
|
this.latestPlaylists = this.latestPlaylists.concat(response.playlists)
|
||||||
this.isElementListLoading = false
|
this.isElementListLoading = false
|
||||||
}).catch((error) => {
|
}).catch((err) => {
|
||||||
console.log(error)
|
console.log(err)
|
||||||
|
if (this.backendPreference === 'invidious' && this.backendFallback) {
|
||||||
|
console.log('Falling back to Local API')
|
||||||
|
this.getPlaylistsLocal()
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
// TODO: Show toast with error message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -324,13 +396,24 @@ export default Vue.extend({
|
||||||
this.searchResults = response.items
|
this.searchResults = response.items
|
||||||
this.isElementListLoading = false
|
this.isElementListLoading = false
|
||||||
this.searchContinuationString = response.continuation
|
this.searchContinuationString = response.continuation
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
if (this.backendPreference === 'local' && this.backendFallback) {
|
||||||
|
console.log('Falling back to Invidious API')
|
||||||
|
this.searchChannelInvidious()
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
// TODO: Show toast with error message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
ytch.searchChannelMore(this.id, this.searchContinuationString).then((response) => {
|
ytch.searchChannelMore(this.searchContinuationString).then((response) => {
|
||||||
console.log(response)
|
console.log(response)
|
||||||
this.searchResults = this.searchResults.concat(response.items)
|
this.searchResults = this.searchResults.concat(response.items)
|
||||||
this.isElementListLoading = false
|
this.isElementListLoading = false
|
||||||
this.searchContinuationString = response.continuation
|
this.searchContinuationString = response.continuation
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -349,6 +432,15 @@ export default Vue.extend({
|
||||||
this.searchResults = this.searchResults.concat(response)
|
this.searchResults = this.searchResults.concat(response)
|
||||||
this.isElementListLoading = false
|
this.isElementListLoading = false
|
||||||
this.searchPage++
|
this.searchPage++
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
if (this.backendPreference === 'invidious' && this.backendFallback) {
|
||||||
|
console.log('Falling back to Local API')
|
||||||
|
this.searchChannelLocal()
|
||||||
|
} else {
|
||||||
|
this.isLoading = false
|
||||||
|
// TODO: Show toast with error message
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,14 @@
|
||||||
class="card"
|
class="card"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
v-if="bannerUrl !== null"
|
||||||
class="channelBanner"
|
class="channelBanner"
|
||||||
:src="bannerUrl"
|
:src="bannerUrl"
|
||||||
>
|
>
|
||||||
|
<img
|
||||||
|
v-else
|
||||||
|
class="defaultChannelBanner"
|
||||||
|
>
|
||||||
<div class="channelInfoContainer">
|
<div class="channelInfoContainer">
|
||||||
<div class="channelInfo">
|
<div class="channelInfo">
|
||||||
<img
|
<img
|
||||||
|
@ -102,8 +107,14 @@
|
||||||
v-html="channelDescription"
|
v-html="channelDescription"
|
||||||
/>
|
/>
|
||||||
<br>
|
<br>
|
||||||
<h2>Featured Channels</h2>
|
<h2
|
||||||
<ft-flex-box>
|
v-if="relatedChannels.length > 0"
|
||||||
|
>
|
||||||
|
Featured Channels
|
||||||
|
</h2>
|
||||||
|
<ft-flex-box
|
||||||
|
v-if="relatedChannels.length > 0"
|
||||||
|
>
|
||||||
<ft-channel-bubble
|
<ft-channel-bubble
|
||||||
v-for="(channel, index) in relatedChannels"
|
v-for="(channel, index) in relatedChannels"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
@ -124,15 +135,37 @@
|
||||||
v-show="currentTab === 'videos'"
|
v-show="currentTab === 'videos'"
|
||||||
:data="latestVideos"
|
:data="latestVideos"
|
||||||
/>
|
/>
|
||||||
|
<ft-flex-box
|
||||||
|
v-if="currentTab === 'videos' && latestVideos.length === 0"
|
||||||
|
>
|
||||||
|
<p class="message">
|
||||||
|
This channel does not currently have any videos
|
||||||
|
</p>
|
||||||
|
</ft-flex-box>
|
||||||
<ft-element-list
|
<ft-element-list
|
||||||
v-show="currentTab === 'playlists'"
|
v-show="currentTab === 'playlists'"
|
||||||
:data="latestPlaylists"
|
:data="latestPlaylists"
|
||||||
/>
|
/>
|
||||||
|
<ft-flex-box
|
||||||
|
v-if="currentTab === 'playlists' && latestPlaylists.length === 0"
|
||||||
|
>
|
||||||
|
<p class="message">
|
||||||
|
This channel does not currently have any playlists
|
||||||
|
</p>
|
||||||
|
</ft-flex-box>
|
||||||
<ft-element-list
|
<ft-element-list
|
||||||
v-show="currentTab === 'search'"
|
v-show="currentTab === 'search'"
|
||||||
:data="searchResults"
|
:data="searchResults"
|
||||||
/>
|
/>
|
||||||
|
<ft-flex-box
|
||||||
|
v-if="currentTab === 'search' && searchResults.length === 0"
|
||||||
|
>
|
||||||
|
<p class="message">
|
||||||
|
Your search results have returned 0 results
|
||||||
|
</p>
|
||||||
|
</ft-flex-box>
|
||||||
<div
|
<div
|
||||||
|
v-if="showFetchMoreButton"
|
||||||
class="getNextPage"
|
class="getNextPage"
|
||||||
@click="handleFetchMore"
|
@click="handleFetchMore"
|
||||||
>
|
>
|
||||||
|
|
|
@ -12,4 +12,7 @@
|
||||||
.playlistItems {
|
.playlistItems {
|
||||||
float: right;
|
float: right;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
|
padding: 10px;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,14 @@
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
class="playlistItems"
|
class="playlistItems"
|
||||||
>
|
>
|
||||||
<ft-flex-box>
|
|
||||||
<ft-list-video
|
<ft-list-video
|
||||||
v-for="(item, index) in playlistItems"
|
v-for="(item, index) in playlistItems"
|
||||||
:key="index"
|
:key="index"
|
||||||
:data="item"
|
:data="item"
|
||||||
:playlist-id="playlistId"
|
:playlist-id="playlistId"
|
||||||
|
appearance="result"
|
||||||
force-list-type="list"
|
force-list-type="list"
|
||||||
class="playlistItem"
|
|
||||||
/>
|
/>
|
||||||
</ft-flex-box>
|
|
||||||
</ft-card>
|
</ft-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
line-height: 45px;
|
line-height: 45px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
|
|
@ -214,8 +214,13 @@ export default Vue.extend({
|
||||||
this.videoDislikeCount = result.videoDetails.dislikes
|
this.videoDislikeCount = result.videoDetails.dislikes
|
||||||
this.isLive = result.player_response.videoDetails.isLive
|
this.isLive = result.player_response.videoDetails.isLive
|
||||||
|
|
||||||
|
if (this.videoDislikeCount === null) {
|
||||||
|
this.videoDislikeCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
const subCount = result.videoDetails.author.subscriber_count
|
const subCount = result.videoDetails.author.subscriber_count
|
||||||
|
|
||||||
|
if (typeof (subCount) !== 'undefined') {
|
||||||
if (subCount >= 1000000) {
|
if (subCount >= 1000000) {
|
||||||
this.channelSubscriptionCountText = `${subCount / 1000000}M`
|
this.channelSubscriptionCountText = `${subCount / 1000000}M`
|
||||||
} else if (subCount >= 10000) {
|
} else if (subCount >= 10000) {
|
||||||
|
@ -223,6 +228,7 @@ export default Vue.extend({
|
||||||
} else {
|
} else {
|
||||||
this.channelSubscriptionCountText = subCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
this.channelSubscriptionCountText = subCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isLive) {
|
if (this.isLive) {
|
||||||
this.showLegacyPlayer = true
|
this.showLegacyPlayer = true
|
||||||
|
|
|
@ -50,8 +50,10 @@
|
||||||
min-width: 380px
|
min-width: 380px
|
||||||
|
|
||||||
.watchVideoPlaylist, .watchVideoSidebar, .theatrePlaylist
|
.watchVideoPlaylist, .watchVideoSidebar, .theatrePlaylist
|
||||||
height: 500px
|
|
||||||
margin: 0 8px 16px
|
margin: 0 8px 16px
|
||||||
|
|
||||||
|
.watchVideoSidebar, .theatrePlaylist
|
||||||
|
height: 500px
|
||||||
|
|
||||||
.watchVideoRecommendations, .theatreRecommendations
|
.watchVideoRecommendations, .theatreRecommendations
|
||||||
margin: 0 8px 16px
|
margin: 0 8px 16px
|
||||||
|
|