mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Format registry folder
This commit is contained in:
parent
8455bb3f41
commit
56d1f0b0d6
@ -25,8 +25,5 @@ export const component: ComponentMetadata = {
|
||||
},
|
||||
entry,
|
||||
urlInclude: feedsUrls,
|
||||
tags: [
|
||||
componentsTags.feeds,
|
||||
componentsTags.utils,
|
||||
],
|
||||
tags: [componentsTags.feeds, componentsTags.utils],
|
||||
}
|
||||
|
||||
@ -18,37 +18,50 @@ const entry = async () => {
|
||||
addStyle()
|
||||
const disableDetails = (card: FeedsCard) => {
|
||||
const { element } = card
|
||||
element.addEventListener('click', e => {
|
||||
if (e.ctrlKey || !enabled) {
|
||||
return
|
||||
}
|
||||
const contents = dqa(element, '.content, .bili-dyn-content [data-module="desc"] .bili-rich-text')
|
||||
const target = e.target as HTMLElement
|
||||
if (target.hasAttribute('click-title')) {
|
||||
return
|
||||
}
|
||||
if ([
|
||||
'bili-rich-text__action',
|
||||
'bili-rich-text-topic',
|
||||
'bili-rich-text-module',
|
||||
'bili-rich-text-link',
|
||||
].some(className => target.classList.contains(className))) {
|
||||
return
|
||||
}
|
||||
const popups = dqa(element, '.im-popup')
|
||||
if (popups.some(p => p.contains(target))) {
|
||||
return
|
||||
}
|
||||
if (contents.some(c => c === target || c.contains(target))) {
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
}, { capture: true })
|
||||
element.addEventListener(
|
||||
'click',
|
||||
e => {
|
||||
if (e.ctrlKey || !enabled) {
|
||||
return
|
||||
}
|
||||
const contents = dqa(
|
||||
element,
|
||||
'.content, .bili-dyn-content [data-module="desc"] .bili-rich-text',
|
||||
)
|
||||
const target = e.target as HTMLElement
|
||||
if (target.hasAttribute('click-title')) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
[
|
||||
'bili-rich-text__action',
|
||||
'bili-rich-text-topic',
|
||||
'bili-rich-text-module',
|
||||
'bili-rich-text-link',
|
||||
].some(className => target.classList.contains(className))
|
||||
) {
|
||||
return
|
||||
}
|
||||
const popups = dqa(element, '.im-popup')
|
||||
if (popups.some(p => p.contains(target))) {
|
||||
return
|
||||
}
|
||||
if (contents.some(c => c === target || c.contains(target))) {
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
},
|
||||
{ capture: true },
|
||||
)
|
||||
const postContent = dq(element, '.post-content, .bili-dyn-content')
|
||||
if (!postContent) {
|
||||
return
|
||||
}
|
||||
const hasCardContainer = ['.video-container', '.bangumi-container', '.media-list', '.article-container']
|
||||
.some(type => dq(postContent, type))
|
||||
const hasCardContainer = [
|
||||
'.video-container',
|
||||
'.bangumi-container',
|
||||
'.media-list',
|
||||
'.article-container',
|
||||
].some(type => dq(postContent, type))
|
||||
if (hasCardContainer) {
|
||||
return
|
||||
}
|
||||
@ -63,7 +76,7 @@ const entry = async () => {
|
||||
const details = document.createElement('div')
|
||||
details.classList.add('details')
|
||||
details.setAttribute('click-title', '详情')
|
||||
details.innerHTML = /* html */`
|
||||
details.innerHTML = /* html */ `
|
||||
详情<i class="mdi mdi-chevron-right" click-title></i>
|
||||
`
|
||||
contents.insertAdjacentElement('beforeend', details)
|
||||
@ -76,9 +89,7 @@ const entry = async () => {
|
||||
export const component: ComponentMetadata = {
|
||||
name: 'disableFeedsDetails',
|
||||
displayName: '禁止跳转动态详情',
|
||||
tags: [
|
||||
componentsTags.feeds,
|
||||
],
|
||||
tags: [componentsTags.feeds],
|
||||
urlInclude: feedsUrls,
|
||||
description: {
|
||||
'zh-CN': '禁止动态点击后跳转详情页, 方便选择其中的文字.',
|
||||
|
||||
@ -13,14 +13,17 @@ interface LiveInfo {
|
||||
}
|
||||
const entry = async () => {
|
||||
const { select } = await import('@/core/spin-query')
|
||||
const liveList = await select('.live-up-list, .bili-dyn-live-users__body') as HTMLElement
|
||||
const liveList = (await select('.live-up-list, .bili-dyn-live-users__body')) as HTMLElement
|
||||
if (liveList === null) {
|
||||
return
|
||||
}
|
||||
const pageSize = 24
|
||||
const { getPages, getJsonWithCredentials } = await import('@/core/ajax')
|
||||
const fullList: LiveInfo[] = await getPages({
|
||||
api: page => getJsonWithCredentials(`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=${pageSize}`),
|
||||
api: page =>
|
||||
getJsonWithCredentials(
|
||||
`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=${pageSize}`,
|
||||
),
|
||||
getList: json => lodash.get(json, 'data.list', []),
|
||||
getTotal: json => lodash.get(json, 'data.results', 0),
|
||||
})
|
||||
@ -46,7 +49,10 @@ const entry = async () => {
|
||||
window.open(url, '_blank')
|
||||
})
|
||||
}
|
||||
const face = dq(clone, '.live-up-img, .bili-dyn-live-users__item__face .bili-awesome-img') as HTMLElement
|
||||
const face = dq(
|
||||
clone,
|
||||
'.live-up-img, .bili-dyn-live-users__item__face .bili-awesome-img',
|
||||
) as HTMLElement
|
||||
face.style.backgroundImage = `url(${it.face})`
|
||||
const title = dq(clone, '.live-name, .bili-dyn-live-users__item__title') as HTMLElement
|
||||
title.innerHTML = it.title
|
||||
@ -70,11 +76,6 @@ export const component: ComponentMetadata = {
|
||||
'zh-CN': '在动态的`正在直播`中, 为每一个直播间加上标题, 并且能够显示超过10个的直播间.',
|
||||
},
|
||||
entry: styledComponentEntry(() => import('./extend-feeds-live.scss'), entry),
|
||||
tags: [
|
||||
componentsTags.feeds,
|
||||
componentsTags.live,
|
||||
],
|
||||
urlInclude: [
|
||||
/^https:\/\/t\.bilibili\.com\/$/,
|
||||
],
|
||||
tags: [componentsTags.feeds, componentsTags.live],
|
||||
urlInclude: [/^https:\/\/t\.bilibili\.com\/$/],
|
||||
}
|
||||
|
||||
@ -6,12 +6,7 @@
|
||||
</div>
|
||||
<h2>类型</h2>
|
||||
<div class="filter-types">
|
||||
<FilterTypeSwitch
|
||||
v-for="[name, type] of allTypes"
|
||||
:key="type.id"
|
||||
:name="name"
|
||||
:type="type"
|
||||
/>
|
||||
<FilterTypeSwitch v-for="[name, type] of allTypes" :key="type.id" :name="name" :type="type" />
|
||||
</div>
|
||||
<h2>关键词</h2>
|
||||
<div class="filter-patterns">
|
||||
@ -45,10 +40,7 @@
|
||||
@click="toggleBlockSide(id)"
|
||||
>
|
||||
<label :class="{ disabled: sideDisabled(id) }">
|
||||
<span
|
||||
class="name"
|
||||
:class="{ disabled: sideDisabled(id) }"
|
||||
>{{ type.displayName }}</span>
|
||||
<span class="name" :class="{ disabled: sideDisabled(id) }">{{ type.displayName }}</span>
|
||||
<VIcon :size="16" class="disabled" icon="mdi-cancel"></VIcon>
|
||||
<VIcon :size="16" icon="mdi-check"></VIcon>
|
||||
</label>
|
||||
@ -62,11 +54,7 @@ import { FeedsCard, FeedsCardType } from '@/components/feeds/api'
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
import { select } from '@/core/spin-query'
|
||||
import { attributes } from '@/core/observer'
|
||||
import {
|
||||
VIcon,
|
||||
TextBox,
|
||||
VButton,
|
||||
} from '@/ui'
|
||||
import { VIcon, TextBox, VButton } from '@/ui'
|
||||
import { FeedsFilterOptions } from '.'
|
||||
import { hasBlockedPattern } from './pattern'
|
||||
|
||||
@ -158,14 +146,9 @@ export default Vue.extend({
|
||||
},
|
||||
})
|
||||
if (cardsManager.managerType === 'v1') {
|
||||
const tab = tabBar.querySelector(
|
||||
'.tab:nth-child(1) .tab-text',
|
||||
) as HTMLAnchorElement
|
||||
const tab = tabBar.querySelector('.tab:nth-child(1) .tab-text') as HTMLAnchorElement
|
||||
attributes(tab, () => {
|
||||
document.body.classList.toggle(
|
||||
'by-type',
|
||||
!tab.classList.contains('selected'),
|
||||
)
|
||||
document.body.classList.toggle('by-type', !tab.classList.contains('selected'))
|
||||
})
|
||||
}
|
||||
if (cardsManager.managerType === 'v2') {
|
||||
@ -206,9 +189,7 @@ export default Vue.extend({
|
||||
updateBlockSide() {
|
||||
Object.entries(sideCards).forEach(([id, type]) => {
|
||||
const name = sideBlock + type.className
|
||||
document.body.classList[
|
||||
this.blockSideCards.includes(id) ? 'add' : 'remove'
|
||||
](name)
|
||||
document.body.classList[this.blockSideCards.includes(id) ? 'add' : 'remove'](name)
|
||||
})
|
||||
},
|
||||
toggleBlockSide(id: number) {
|
||||
@ -231,8 +212,8 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "./blocker";
|
||||
@import 'common';
|
||||
@import './blocker';
|
||||
|
||||
body.enable-feeds-filter:not(.disable-feeds-filter) {
|
||||
@include type-block();
|
||||
|
||||
@ -11,9 +11,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
import {
|
||||
VIcon,
|
||||
} from '@/ui'
|
||||
import { VIcon } from '@/ui'
|
||||
|
||||
const { options } = getComponentSettings('feedsFilter')
|
||||
export default Vue.extend({
|
||||
@ -48,9 +46,7 @@ export default Vue.extend({
|
||||
},
|
||||
methods: {
|
||||
setFilter(disabled: boolean, updateSettings = true) {
|
||||
document.body.classList[disabled ? 'add' : 'remove'](
|
||||
`feeds-filter-block-${this.name}`,
|
||||
)
|
||||
document.body.classList[disabled ? 'add' : 'remove'](`feeds-filter-block-${this.name}`)
|
||||
if (!updateSettings) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -57,9 +57,7 @@ export const component: ComponentMetadata = {
|
||||
'zh-CN': '按照类型或者关键词过滤动态首页的内容, 也可以移除动态页的一些侧边卡片.',
|
||||
},
|
||||
entry,
|
||||
tags: [
|
||||
componentsTags.feeds,
|
||||
],
|
||||
tags: [componentsTags.feeds],
|
||||
options,
|
||||
reload: () => document.body.classList.remove('disable-feeds-filter'),
|
||||
unload: () => document.body.classList.add('disable-feeds-filter'),
|
||||
|
||||
@ -15,10 +15,7 @@ export interface BlockableCard {
|
||||
export const hasBlockedPattern = (pattern: string, card: BlockableCard) => {
|
||||
const upNameMatch = pattern.match(/(.+) up:([^ ]+)/)
|
||||
if (upNameMatch) {
|
||||
return (
|
||||
testPattern(upNameMatch[1], card.text)
|
||||
&& testPattern(upNameMatch[2], card.username)
|
||||
)
|
||||
return testPattern(upNameMatch[1], card.text) && testPattern(upNameMatch[2], card.username)
|
||||
}
|
||||
return testPattern(pattern, card.text)
|
||||
}
|
||||
|
||||
@ -14,11 +14,7 @@ const feedField = {
|
||||
username: ['username', 'repostUsername'],
|
||||
text: ['text', 'repostText'],
|
||||
}
|
||||
const filterableFields = [
|
||||
bangumiFields,
|
||||
videoField,
|
||||
feedField,
|
||||
]
|
||||
const filterableFields = [bangumiFields, videoField, feedField]
|
||||
export const feedsFilterPlugin: PluginMetadata = {
|
||||
name: 'feeds.contentFilters.patterns',
|
||||
displayName: '动态关键词过滤',
|
||||
@ -32,18 +28,24 @@ export const feedsFilterPlugin: PluginMetadata = {
|
||||
patterns: string[]
|
||||
}
|
||||
return items.filter(item => {
|
||||
const field = filterableFields.find(it => (
|
||||
const field = filterableFields.find(it =>
|
||||
Object.values(it).every(fields => {
|
||||
if (Array.isArray(fields)) {
|
||||
return fields.some(f => f in item)
|
||||
}
|
||||
return fields in item
|
||||
})
|
||||
))
|
||||
}),
|
||||
)
|
||||
const card = Object.fromEntries(
|
||||
Object.entries(field).map(([key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
return [key, value.map(v => item[v] ?? '').join('\n').trim()]
|
||||
return [
|
||||
key,
|
||||
value
|
||||
.map(v => item[v] ?? '')
|
||||
.join('\n')
|
||||
.trim(),
|
||||
]
|
||||
}
|
||||
return [key, item[value].trim() as string]
|
||||
}),
|
||||
|
||||
@ -19,11 +19,7 @@ export const component: ComponentMetadata = {
|
||||
description: {
|
||||
'zh-CN': '强制固定动态主页的顶栏和所有侧栏.',
|
||||
},
|
||||
tags: [
|
||||
componentsTags.feeds,
|
||||
],
|
||||
tags: [componentsTags.feeds],
|
||||
entry,
|
||||
urlInclude: [
|
||||
/^https:\/\/t\.bilibili\.com\/$/,
|
||||
],
|
||||
urlInclude: [/^https:\/\/t\.bilibili\.com\/$/],
|
||||
}
|
||||
|
||||
@ -83,8 +83,6 @@ export const component: ComponentMetadata = {
|
||||
'zh-CN': '动态里查看评论区时, 在底部添加一个`收起评论`按钮, 这样就不用再回到上面收起了.',
|
||||
},
|
||||
urlInclude: feedsUrlsWithoutDetail,
|
||||
tags: [
|
||||
componentsTags.feeds,
|
||||
],
|
||||
tags: [componentsTags.feeds],
|
||||
entry: styledComponentEntry(() => import('./fold-comment.scss'), entry),
|
||||
}
|
||||
|
||||
@ -8,9 +8,6 @@ export const component: ComponentMetadata = {
|
||||
description: {
|
||||
'zh-CN': '不管内容多长, 总是完全展开动态的内容.',
|
||||
},
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.feeds,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.feeds],
|
||||
urlInclude: feedsUrlsWithoutDetail,
|
||||
}
|
||||
|
||||
@ -22,11 +22,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</VPopup>
|
||||
<DefaultWidget
|
||||
ref="medalButton"
|
||||
icon="mdi-medal"
|
||||
@click="medalOpen = !medalOpen"
|
||||
>
|
||||
<DefaultWidget ref="medalButton" icon="mdi-medal" @click="medalOpen = !medalOpen">
|
||||
<span>更换勋章</span>
|
||||
</DefaultWidget>
|
||||
|
||||
@ -48,11 +44,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</VPopup>
|
||||
<DefaultWidget
|
||||
ref="titleButton"
|
||||
icon="mdi-script-outline"
|
||||
@click="titleOpen = !titleOpen"
|
||||
>
|
||||
<DefaultWidget ref="titleButton" icon="mdi-script-outline" @click="titleOpen = !titleOpen">
|
||||
<span>更换头衔</span>
|
||||
</DefaultWidget>
|
||||
</div>
|
||||
@ -61,13 +53,8 @@
|
||||
<script lang="ts">
|
||||
import { addComponentListener, getComponentSettings } from '@/core/settings'
|
||||
import { descendingSort } from '@/core/utils/sort'
|
||||
import {
|
||||
DefaultWidget,
|
||||
VPopup,
|
||||
} from '@/ui'
|
||||
import {
|
||||
Medal, Title, Badge, getMedalList, getTitleList,
|
||||
} from './badge'
|
||||
import { DefaultWidget, VPopup } from '@/ui'
|
||||
import { Medal, Title, Badge, getMedalList, getTitleList } from './badge'
|
||||
|
||||
const { options } = getComponentSettings('badgeHelper')
|
||||
export default Vue.extend({
|
||||
@ -85,9 +72,13 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
addComponentListener('badgeHelper.grayEffect', (enable: boolean) => {
|
||||
this.grayEffect = enable
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'badgeHelper.grayEffect',
|
||||
(enable: boolean) => {
|
||||
this.grayEffect = enable
|
||||
},
|
||||
true,
|
||||
)
|
||||
const init = async () => {
|
||||
const medal = this.loadMedalList()
|
||||
await Title.getImageMap()
|
||||
@ -142,7 +133,7 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
.badge-popup {
|
||||
top: 50%;
|
||||
left: calc(100% + 8px);
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import { getJsonWithCredentials, getPages, getTextWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
||||
import {
|
||||
getJsonWithCredentials,
|
||||
getPages,
|
||||
getTextWithCredentials,
|
||||
postTextWithCredentials,
|
||||
} from '@/core/ajax'
|
||||
import { formData, getCsrf } from '@/core/utils'
|
||||
import { logError } from '@/core/utils/log'
|
||||
|
||||
@ -12,13 +17,16 @@ const validateJson = (json: any, errorMessage: string) => {
|
||||
}
|
||||
|
||||
export abstract class Badge {
|
||||
constructor(public isActive: boolean = false, public id: number = 0) { }
|
||||
constructor(public isActive: boolean = false, public id: number = 0) {}
|
||||
/** @deprecated */
|
||||
static parseJson<T>(text: string, actions: {
|
||||
successAction: (json: any) => T,
|
||||
errorMessage: string,
|
||||
errorAction: (json: any) => T
|
||||
}) {
|
||||
static parseJson<T>(
|
||||
text: string,
|
||||
actions: {
|
||||
successAction: (json: any) => T
|
||||
errorMessage: string
|
||||
errorAction: (json: any) => T
|
||||
},
|
||||
) {
|
||||
const json = JSON.parse(text)
|
||||
if (json.code !== 0) {
|
||||
logError(`${actions.errorMessage} 错误码:${json.code} ${json.message || ''}`)
|
||||
@ -37,19 +45,9 @@ export class Medal extends Badge {
|
||||
isLighted: boolean
|
||||
constructor(json: any) {
|
||||
const {
|
||||
medal: {
|
||||
medal_id,
|
||||
level,
|
||||
medal_name,
|
||||
wearing_status,
|
||||
is_lighted,
|
||||
},
|
||||
anchor_info: {
|
||||
nick_name,
|
||||
},
|
||||
room_info: {
|
||||
room_id,
|
||||
},
|
||||
medal: { medal_id, level, medal_name, wearing_status, is_lighted },
|
||||
anchor_info: { nick_name },
|
||||
room_info: { room_id },
|
||||
} = json
|
||||
super(wearing_status === 1, medal_id)
|
||||
this.level = level
|
||||
@ -59,20 +57,26 @@ export class Medal extends Badge {
|
||||
this.isLighted = is_lighted
|
||||
}
|
||||
async activate() {
|
||||
const text = await postTextWithCredentials('https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/wear', formData({
|
||||
medal_id: this.id,
|
||||
csrf_token: getCsrf(),
|
||||
csrf: getCsrf(),
|
||||
}))
|
||||
const text = await postTextWithCredentials(
|
||||
'https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/wear',
|
||||
formData({
|
||||
medal_id: this.id,
|
||||
csrf_token: getCsrf(),
|
||||
csrf: getCsrf(),
|
||||
}),
|
||||
)
|
||||
const result = validateJson(JSON.parse(text), '佩戴勋章失败.')
|
||||
this.isActive = true
|
||||
return result
|
||||
}
|
||||
async deactivate() {
|
||||
const text = await postTextWithCredentials('https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/take_off', formData({
|
||||
csrf_token: getCsrf(),
|
||||
csrf: getCsrf(),
|
||||
}))
|
||||
const text = await postTextWithCredentials(
|
||||
'https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/take_off',
|
||||
formData({
|
||||
csrf_token: getCsrf(),
|
||||
csrf: getCsrf(),
|
||||
}),
|
||||
)
|
||||
const result = validateJson(JSON.parse(text), '卸下勋章失败.')
|
||||
this.isActive = false
|
||||
return result
|
||||
@ -80,13 +84,13 @@ export class Medal extends Badge {
|
||||
}
|
||||
export const getMedalList = async () => {
|
||||
const pages = await getPages({
|
||||
api: page => getJsonWithCredentials(`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/panel?page=${page}&page_size=50`),
|
||||
api: page =>
|
||||
getJsonWithCredentials(
|
||||
`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/panel?page=${page}&page_size=50`,
|
||||
),
|
||||
getList: json => {
|
||||
validateJson(json, '无法获取勋章列表.')
|
||||
return [
|
||||
...lodash.get(json, 'data.list', []),
|
||||
...lodash.get(json, 'data.special_list', []),
|
||||
]
|
||||
return [...lodash.get(json, 'data.list', []), ...lodash.get(json, 'data.special_list', [])]
|
||||
},
|
||||
getTotal: json => lodash.get(json, 'data.total_number', 0),
|
||||
})
|
||||
@ -100,9 +104,7 @@ export class Title extends Badge {
|
||||
source: string
|
||||
imageUrl: string
|
||||
constructor(json: any) {
|
||||
const {
|
||||
id, cid, wear, css, name, source,
|
||||
} = json
|
||||
const { id, cid, wear, css, name, source } = json
|
||||
super(wear, css)
|
||||
this.tid = id
|
||||
this.cid = cid
|
||||
@ -134,7 +136,10 @@ export class Title extends Badge {
|
||||
}
|
||||
async activate() {
|
||||
return Badge.parseJson(
|
||||
await postTextWithCredentials('https://api.live.bilibili.com/i/ajaxWearTitle', `id=${this.tid}&cid=${this.cid}&csrf=${getCsrf()}&csrf_token=${getCsrf()}`),
|
||||
await postTextWithCredentials(
|
||||
'https://api.live.bilibili.com/i/ajaxWearTitle',
|
||||
`id=${this.tid}&cid=${this.cid}&csrf=${getCsrf()}&csrf_token=${getCsrf()}`,
|
||||
),
|
||||
{
|
||||
successAction: () => {
|
||||
this.isActive = true
|
||||
@ -147,8 +152,10 @@ export class Title extends Badge {
|
||||
}
|
||||
async deactivate() {
|
||||
return Badge.parseJson(
|
||||
await postTextWithCredentials('https://api.live.bilibili.com/i/ajaxCancelWearTitle',
|
||||
`csrf=${getCsrf()}&csrf_token=${getCsrf()}`),
|
||||
await postTextWithCredentials(
|
||||
'https://api.live.bilibili.com/i/ajaxCancelWearTitle',
|
||||
`csrf=${getCsrf()}&csrf_token=${getCsrf()}`,
|
||||
),
|
||||
{
|
||||
successAction: () => {
|
||||
this.isActive = false
|
||||
@ -160,11 +167,15 @@ export class Title extends Badge {
|
||||
)
|
||||
}
|
||||
}
|
||||
export const getTitleList = async () => Badge.parseJson(
|
||||
await getTextWithCredentials('https://api.live.bilibili.com/i/api/ajaxTitleInfo?page=1&pageSize=256&had=1'),
|
||||
{
|
||||
successAction: json => lodash.get(json, 'data.list', []).map((it: any) => new Title(it)) as Title[],
|
||||
errorAction: () => [] as Title[],
|
||||
errorMessage: '无法获取头衔列表.',
|
||||
},
|
||||
)
|
||||
export const getTitleList = async () =>
|
||||
Badge.parseJson(
|
||||
await getTextWithCredentials(
|
||||
'https://api.live.bilibili.com/i/api/ajaxTitleInfo?page=1&pageSize=256&had=1',
|
||||
),
|
||||
{
|
||||
successAction: json =>
|
||||
lodash.get(json, 'data.list', []).map((it: any) => new Title(it)) as Title[],
|
||||
errorAction: () => [] as Title[],
|
||||
errorMessage: '无法获取头衔列表.',
|
||||
},
|
||||
)
|
||||
|
||||
@ -6,14 +6,13 @@ export const component = defineComponentMetadata({
|
||||
name: 'badgeHelper',
|
||||
displayName: '直播勋章快速更换',
|
||||
description: {
|
||||
'zh-CN': '在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改.',
|
||||
'zh-CN':
|
||||
'在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改.',
|
||||
},
|
||||
entry: () => autoMatchMedal(),
|
||||
reload: none,
|
||||
unload: none,
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
],
|
||||
tags: [componentsTags.live],
|
||||
widget: {
|
||||
component: () => import('./BadgeHelper.vue').then(m => m.default),
|
||||
condition: () => Boolean(getUID()),
|
||||
@ -38,7 +37,5 @@ export const component = defineComponentMetadata({
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
urlInclude: [
|
||||
'//live.bilibili.com',
|
||||
],
|
||||
urlInclude: ['//live.bilibili.com'],
|
||||
})
|
||||
|
||||
@ -25,10 +25,14 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const originalTextArea = await select(originalTextAreaSelector) as HTMLTextAreaElement
|
||||
const sendButton = await select(sendButtonSelector) as HTMLButtonElement
|
||||
const originalTextArea = (await select(originalTextAreaSelector)) as HTMLTextAreaElement
|
||||
const sendButton = (await select(sendButtonSelector)) as HTMLButtonElement
|
||||
if (!originalTextArea || !sendButton) {
|
||||
throw new Error(`[danmakuSendBar] ref elements not found. originalTextArea = ${originalTextArea === null} sendButton = ${sendButton === null}`)
|
||||
throw new Error(
|
||||
`[danmakuSendBar] ref elements not found. originalTextArea = ${
|
||||
originalTextArea === null
|
||||
} sendButton = ${sendButton === null}`,
|
||||
)
|
||||
}
|
||||
// console.log(originalTextArea, sendButton)
|
||||
this.originalTextArea = originalTextArea
|
||||
@ -37,9 +41,7 @@ export default Vue.extend({
|
||||
originalTextArea.addEventListener('input', this.listenChange)
|
||||
originalTextArea.addEventListener('change', this.listenChange)
|
||||
if (!changeEventHook) {
|
||||
const original = Object.getOwnPropertyDescriptors(
|
||||
HTMLTextAreaElement.prototype,
|
||||
).value
|
||||
const original = Object.getOwnPropertyDescriptors(HTMLTextAreaElement.prototype).value
|
||||
Object.defineProperty(originalTextArea, 'value', {
|
||||
...original,
|
||||
set(value: string) {
|
||||
|
||||
@ -30,9 +30,7 @@ const entry = async () => {
|
||||
export const component = defineComponentMetadata({
|
||||
name: 'liveDanmakuSendbar',
|
||||
displayName: '直播弹幕发送栏',
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
],
|
||||
tags: [componentsTags.live],
|
||||
description: {
|
||||
'zh-CN': '在直播的网页全屏和全屏模式状态下, 在底部显示弹幕栏.',
|
||||
},
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export const originalTextAreaSelector = '.control-panel-ctnr .chat-input-ctnr .chat-input'
|
||||
export const sendButtonSelector = '.control-panel-ctnr .chat-input-ctnr ~ .bottom-actions .bl-button--primary'
|
||||
export const sendButtonSelector =
|
||||
'.control-panel-ctnr .chat-input-ctnr ~ .bottom-actions .bl-button--primary'
|
||||
export const leftControllerSelector = '.left-area'
|
||||
|
||||
@ -43,7 +43,12 @@ export default Vue.extend({
|
||||
return
|
||||
}
|
||||
const links: string[] = json.data.list.map((it: { url: string }) => it.url)
|
||||
Toast.success(links.map(l => `<a class="download-link" target="_blank" href="${l}">${l}</a>`).join('\n'), '下载录像')
|
||||
Toast.success(
|
||||
links
|
||||
.map(l => `<a class="download-link" target="_blank" href="${l}">${l}</a>`)
|
||||
.join('\n'),
|
||||
'下载录像',
|
||||
)
|
||||
} finally {
|
||||
this.disabled = false
|
||||
}
|
||||
|
||||
@ -6,14 +6,10 @@ export const component = defineComponentMetadata({
|
||||
description: {
|
||||
'zh-CN': '在直播录像页面 `live.bilibili.com/record/` 中添加下载支持.',
|
||||
},
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
],
|
||||
tags: [componentsTags.live],
|
||||
entry: none,
|
||||
widget: {
|
||||
component: () => import('./DownloadRecords.vue').then(m => m.default),
|
||||
},
|
||||
urlInclude: [
|
||||
/^https:\/\/live\.bilibili\.com\/record\/(.+)/,
|
||||
],
|
||||
urlInclude: [/^https:\/\/live\.bilibili\.com\/record\/(.+)/],
|
||||
})
|
||||
|
||||
@ -46,7 +46,7 @@ let stopObservingMouseLeavePlayer: StopObservingCallback | null = null
|
||||
interface FullWinToggleCallback {
|
||||
(
|
||||
// 标识监听到的动作是启动操作还是关闭操作
|
||||
isStarted: boolean
|
||||
isStarted: boolean,
|
||||
): void
|
||||
}
|
||||
|
||||
@ -75,9 +75,7 @@ function isFullWin(): boolean {
|
||||
* @param callback 回调函数
|
||||
* @returns 停止监听的函数
|
||||
*/
|
||||
function observeFullWinToggle(
|
||||
onToggle: FullWinToggleCallback,
|
||||
): StopObservingCallback {
|
||||
function observeFullWinToggle(onToggle: FullWinToggleCallback): StopObservingCallback {
|
||||
/**
|
||||
* 检查是否发生了全屏模式的变化
|
||||
* @param {MutationRecord} mutation body 元素的属性变化(不检查变化类型)
|
||||
@ -113,10 +111,7 @@ function observeFullWinToggle(
|
||||
}
|
||||
|
||||
// 将包裹按钮移动到控制条上
|
||||
function moveGiftPackageToControlBar(
|
||||
controlBar: Element,
|
||||
giftBtn0: Element,
|
||||
) {
|
||||
function moveGiftPackageToControlBar(controlBar: Element, giftBtn0: Element) {
|
||||
// console.debug(`[${componentName}] moving gift button to control bar...`)
|
||||
const rightArea = dq(controlBar, '.right-area')
|
||||
if (rightArea) {
|
||||
@ -159,14 +154,9 @@ function onFullWinClose(giftBtn0: Element, originGiftBtnParent: Element) {
|
||||
}
|
||||
|
||||
// 每当全屏模式切换时执行操作
|
||||
function doOnFullWinToggle(
|
||||
giftBtn0: Element,
|
||||
originGiftBtnParent: Element,
|
||||
): StopObservingCallback {
|
||||
function doOnFullWinToggle(giftBtn0: Element, originGiftBtnParent: Element): StopObservingCallback {
|
||||
return observeFullWinToggle(isStarted => {
|
||||
isStarted
|
||||
? onFullWinStart(giftBtn0)
|
||||
: onFullWinClose(giftBtn0, originGiftBtnParent)
|
||||
isStarted ? onFullWinStart(giftBtn0) : onFullWinClose(giftBtn0, originGiftBtnParent)
|
||||
})
|
||||
}
|
||||
|
||||
@ -195,7 +185,7 @@ async function reload() {
|
||||
addStyle(componentStyle, componentName)
|
||||
|
||||
const giftBtnParent = await queryGiftBtnParent()
|
||||
giftBtn = (giftBtnParent?.children[0])
|
||||
giftBtn = giftBtnParent?.children[0]
|
||||
|
||||
if (giftBtnParent && giftBtn) {
|
||||
stopObservingFullWinToggle = doOnFullWinToggle(giftBtn, giftBtnParent)
|
||||
|
||||
@ -6,21 +6,23 @@ const liveHome = /^https:\/\/live\.bilibili\.com\/(index\.html)?$/
|
||||
export const component = defineComponentMetadata({
|
||||
name: 'liveHomeMute',
|
||||
displayName: '直播首页静音',
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
],
|
||||
tags: [componentsTags.live],
|
||||
description: {
|
||||
'zh-CN': '禁止直播首页的推荐直播间自动开始播放.',
|
||||
},
|
||||
entry: async ({ metadata }) => {
|
||||
const styleID = 'hide-home-live'
|
||||
addComponentListener(`${metadata.name}.hide`, (value: boolean) => {
|
||||
if (value) {
|
||||
addStyle('.player-area-ctnr,#player-header { display: none !important }', styleID)
|
||||
} else {
|
||||
removeStyle(styleID)
|
||||
}
|
||||
}, true)
|
||||
addComponentListener(
|
||||
`${metadata.name}.hide`,
|
||||
(value: boolean) => {
|
||||
if (value) {
|
||||
addStyle('.player-area-ctnr,#player-header { display: none !important }', styleID)
|
||||
} else {
|
||||
removeStyle(styleID)
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
},
|
||||
options: {
|
||||
hide: {
|
||||
@ -28,9 +30,7 @@ export const component = defineComponentMetadata({
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
urlInclude: [
|
||||
liveHome,
|
||||
],
|
||||
urlInclude: [liveHome],
|
||||
plugin: {
|
||||
displayName: '直播首页静音 - 提前执行',
|
||||
description: {
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<a :href="href" tabindex="-1">
|
||||
<DefaultWidget
|
||||
name="返回原版直播间"
|
||||
icon="mdi-arrow-left-circle-outline"
|
||||
/>
|
||||
<DefaultWidget name="返回原版直播间" icon="mdi-arrow-left-circle-outline" />
|
||||
</a>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
||||
@ -4,7 +4,8 @@ import { matchUrlPattern } from '@/core/utils'
|
||||
export const component = defineComponentMetadata({
|
||||
name: 'originalLiveroom',
|
||||
displayName: '返回原版直播间',
|
||||
description: '在直播间中提供返回原版直播间的按钮, 原版直播间将无视活动皮肤, 强制使用标准的直播页面.',
|
||||
description:
|
||||
'在直播间中提供返回原版直播间的按钮, 原版直播间将无视活动皮肤, 强制使用标准的直播页面.',
|
||||
tags: [componentsTags.live],
|
||||
entry: none,
|
||||
urlInclude: [
|
||||
|
||||
@ -5,10 +5,7 @@ import { liveUrls } from '@/core/utils/urls'
|
||||
export const component = defineComponentMetadata({
|
||||
...toggleStyle('removeLiveWatermark', () => import('./remove-watermark.scss')),
|
||||
displayName: '删除直播水印',
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.live, componentsTags.style],
|
||||
description: {
|
||||
'zh-CN': '删除观看直播时角落的水印.',
|
||||
},
|
||||
|
||||
@ -5,13 +5,16 @@ const id = 'dpi-live-showgirl'
|
||||
const entry = async () => {
|
||||
const { addStyle } = await import('@/core/style')
|
||||
if (document.getElementById(id) === null) {
|
||||
addStyle(`
|
||||
addStyle(
|
||||
`
|
||||
.haruna-ctnr,
|
||||
.avatar-btn
|
||||
{
|
||||
transform: scale(${1 / window.devicePixelRatio}) !important;
|
||||
}
|
||||
`, id)
|
||||
`,
|
||||
id,
|
||||
)
|
||||
}
|
||||
}
|
||||
export const component = defineComponentMetadata({
|
||||
@ -21,10 +24,7 @@ export const component = defineComponentMetadata({
|
||||
description: {
|
||||
'zh-CN': '根据屏幕 DPI 缩放直播看板娘的大小, 避免像素锯齿.',
|
||||
},
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.live, componentsTags.style],
|
||||
entry,
|
||||
reload: entry,
|
||||
unload: () => {
|
||||
|
||||
@ -12,9 +12,6 @@ export const component = defineComponentMetadata({
|
||||
],
|
||||
displayName: '自动收起直播侧栏',
|
||||
description: '自动收起直播间右边偏下的侧栏. (上面有个 "关注" 的面板)',
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.live, componentsTags.style],
|
||||
urlInclude: liveUrls,
|
||||
})
|
||||
|
||||
@ -5,9 +5,13 @@ import { getNumberValidator } from '@/core/utils'
|
||||
export const component = defineComponentMetadata({
|
||||
name: 'autoHideSidebar',
|
||||
entry: () => {
|
||||
addComponentListener('autoHideSidebar.triggerWidth', (value: number) => {
|
||||
document.documentElement.style.setProperty('--auto-hide-sidebar-width', `${value}px`)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'autoHideSidebar.triggerWidth',
|
||||
(value: number) => {
|
||||
document.documentElement.style.setProperty('--auto-hide-sidebar-width', `${value}px`)
|
||||
},
|
||||
true,
|
||||
)
|
||||
},
|
||||
displayName: '自动隐藏侧栏',
|
||||
instantStyles: [
|
||||
@ -26,6 +30,7 @@ export const component = defineComponentMetadata({
|
||||
},
|
||||
},
|
||||
description: {
|
||||
'zh-CN': '自动隐藏脚本的侧栏 (功能和设置图标). 设置面板停靠在右侧时不建议使用, 因为网页的滚动条会占用右边缘的触发区域.',
|
||||
'zh-CN':
|
||||
'自动隐藏脚本的侧栏 (功能和设置图标). 设置面板停靠在右侧时不建议使用, 因为网页的滚动条会占用右边缘的触发区域.',
|
||||
},
|
||||
})
|
||||
|
||||
@ -2,11 +2,7 @@
|
||||
<div class="custom-navbar" :class="styles" role="navigation">
|
||||
<div class="left-pad padding"></div>
|
||||
<div class="custom-navbar-items" role="list">
|
||||
<NavbarItem
|
||||
v-for="item of items"
|
||||
:key="item.name"
|
||||
:item="item"
|
||||
></NavbarItem>
|
||||
<NavbarItem v-for="item of items" :key="item.name" :item="item"></NavbarItem>
|
||||
</div>
|
||||
<div class="right-pad padding"></div>
|
||||
</div>
|
||||
@ -63,9 +59,13 @@ export default Vue.extend({
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
addComponentListener('customNavbar.height', (value: number) => {
|
||||
document.documentElement.style.setProperty('--navbar-height', `${value}px`)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'customNavbar.height',
|
||||
(value: number) => {
|
||||
document.documentElement.style.setProperty('--navbar-height', `${value}px`)
|
||||
},
|
||||
true,
|
||||
)
|
||||
await checkTransparentFill(this)
|
||||
},
|
||||
methods: {
|
||||
@ -214,12 +214,7 @@ body.fixed-navbar {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(2 * var(--navbar-height));
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
#000a 0,
|
||||
#0004 65%,
|
||||
transparent 100%
|
||||
);
|
||||
background-image: linear-gradient(to bottom, #000a 0, #0004 65%, transparent 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,10 @@ export default Vue.extend({
|
||||
if (!popup) {
|
||||
return
|
||||
}
|
||||
const allowRefresh = CustomNavbarItem.navbarOptions.refreshOnPopup && popup.popupRefresh && typeof popup.popupRefresh === 'function'
|
||||
const allowRefresh =
|
||||
CustomNavbarItem.navbarOptions.refreshOnPopup &&
|
||||
popup.popupRefresh &&
|
||||
typeof popup.popupRefresh === 'function'
|
||||
if (!initialPopup && allowRefresh) {
|
||||
popup.popupRefresh()
|
||||
}
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<a
|
||||
v-bind="$attrs"
|
||||
:target="newTab ? '_blank' : null"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<a v-bind="$attrs" :target="newTab ? '_blank' : null" v-on="$listeners">
|
||||
<slot />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
@ -4,19 +4,9 @@ import { ranking } from './ranking/ranking'
|
||||
import { userInfo } from './user-info/user-info'
|
||||
import { logo } from './logo/logo'
|
||||
import { home } from './home/home'
|
||||
import {
|
||||
gamesIframe,
|
||||
livesIframe,
|
||||
mangaIframe,
|
||||
} from './iframe/iframe'
|
||||
import { gamesIframe, livesIframe, mangaIframe } from './iframe/iframe'
|
||||
import { blanks } from './flexible-blank/flexible-blank'
|
||||
import {
|
||||
bangumi,
|
||||
music,
|
||||
drawing,
|
||||
shop,
|
||||
match,
|
||||
} from './simple-links/simple-links'
|
||||
import { bangumi, music, drawing, shop, match } from './simple-links/simple-links'
|
||||
import { upload } from './upload/upload'
|
||||
import { search } from './search/search'
|
||||
import { feeds } from './feeds/feeds'
|
||||
|
||||
@ -83,9 +83,13 @@ export class CustomNavbarItem implements Required<CustomNavbarItemInit> {
|
||||
throw new Error('Missing CustomNavbarItem content')
|
||||
}
|
||||
|
||||
addComponentListener('customNavbar.touch', (value: boolean) => {
|
||||
this.touch = value ? init.touch : false
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'customNavbar.touch',
|
||||
(value: boolean) => {
|
||||
this.touch = value ? init.touch : false
|
||||
},
|
||||
true,
|
||||
)
|
||||
this.hidden = CustomNavbarItem.navbarOptions.hidden.includes(this.name)
|
||||
const orderMap = CustomNavbarItem.navbarOptions.order
|
||||
this.order = orderMap[this.name] || 0
|
||||
|
||||
@ -1,47 +1,46 @@
|
||||
import { ComponentEntry } from '@/components/types'
|
||||
import { addComponentListener } from '@/core/settings'
|
||||
import {
|
||||
isIframe,
|
||||
isNotHtml,
|
||||
matchUrlPattern,
|
||||
mountVueComponent,
|
||||
} from '@/core/utils'
|
||||
import { isIframe, isNotHtml, matchUrlPattern, mountVueComponent } from '@/core/utils'
|
||||
|
||||
export const entry: ComponentEntry = async ({ metadata: { name } }) => {
|
||||
// const url = document.URL.replace(location.search, '')
|
||||
// const isHome = url === 'https://www.bilibili.com/' || url === 'https://www.bilibili.com/index.html'
|
||||
if (
|
||||
isIframe()
|
||||
isIframe() ||
|
||||
// (getComponentSettings('bilibiliSimpleNewHomeCompatible').enabled && isHome) ||
|
||||
|| isNotHtml()
|
||||
isNotHtml()
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
addComponentListener(`${name}.padding`, value => {
|
||||
document.documentElement.style.setProperty('--navbar-bounds-padding', `${value}%`)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
`${name}.padding`,
|
||||
value => {
|
||||
document.documentElement.style.setProperty('--navbar-bounds-padding', `${value}%`)
|
||||
},
|
||||
true,
|
||||
)
|
||||
const globalFixedExclude = [
|
||||
'https://space.bilibili.com',
|
||||
'https://www.bilibili.com/read',
|
||||
'https://www.bilibili.com/account/history',
|
||||
]
|
||||
if (!globalFixedExclude.some(p => matchUrlPattern(p))) {
|
||||
addComponentListener(`${name}.globalFixed`, value => {
|
||||
document.body.classList.toggle('fixed-navbar', value)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
`${name}.globalFixed`,
|
||||
value => {
|
||||
document.body.classList.toggle('fixed-navbar', value)
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
const CustomNavbar = await import('./CustomNavbar.vue')
|
||||
const customNavbar: Vue & {
|
||||
styles: string[]
|
||||
toggleStyle: (value: boolean, style: string) => void
|
||||
} = mountVueComponent(CustomNavbar)
|
||||
document.body.insertAdjacentElement('beforeend', customNavbar.$el);
|
||||
['fill', 'shadow', 'blur'].forEach(style => {
|
||||
addComponentListener(
|
||||
`${name}.${style}`,
|
||||
value => customNavbar.toggleStyle(value, style),
|
||||
true,
|
||||
)
|
||||
document.body.insertAdjacentElement('beforeend', customNavbar.$el)
|
||||
;['fill', 'shadow', 'blur'].forEach(style => {
|
||||
addComponentListener(`${name}.${style}`, value => customNavbar.toggleStyle(value, style), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,9 +13,7 @@
|
||||
</VDropdown>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
VDropdown,
|
||||
} from '@/ui'
|
||||
import { VDropdown } from '@/ui'
|
||||
import { getUID } from '@/core/utils'
|
||||
import { getJsonWithCredentials } from '@/core/ajax'
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
@ -51,17 +49,14 @@ export default Vue.extend({
|
||||
if (json.code !== 0) {
|
||||
throw new Error(`获取收藏夹列表失败: ${json.message}`)
|
||||
}
|
||||
this.folders = lodash.get(json, 'data.list', []).map((item: {
|
||||
id: number
|
||||
title: string
|
||||
media_count: number
|
||||
}) => (
|
||||
{
|
||||
id: item.id,
|
||||
name: item.title,
|
||||
count: item.media_count,
|
||||
} as FavoritesFolder
|
||||
))
|
||||
this.folders = lodash.get(json, 'data.list', []).map(
|
||||
(item: { id: number; title: string; media_count: number }) =>
|
||||
({
|
||||
id: item.id,
|
||||
name: item.title,
|
||||
count: item.media_count,
|
||||
} as FavoritesFolder),
|
||||
)
|
||||
if (this.folders.length > 0 && this.folder.id === notSelectedFolder.id) {
|
||||
const { lastFavoriteFolder } = navbarOptions
|
||||
const folder = this.folders.find((f: FavoritesFolder) => f.id === lastFavoriteFolder)
|
||||
|
||||
@ -39,7 +39,8 @@
|
||||
target="_blank"
|
||||
:href="'https://www.bilibili.com/video/' + card.bvid"
|
||||
:title="card.title"
|
||||
>{{ card.title }}</a>
|
||||
>{{ card.title }}</a
|
||||
>
|
||||
<a
|
||||
v-if="card.upID"
|
||||
class="up"
|
||||
@ -47,18 +48,10 @@
|
||||
:href="'https://space.bilibili.com/' + card.upID"
|
||||
:title="card.upName"
|
||||
>
|
||||
<DpiImage
|
||||
placeholder-image
|
||||
class="face"
|
||||
:src="card.upFaceUrl"
|
||||
:size="20"
|
||||
></DpiImage>
|
||||
<DpiImage placeholder-image class="face" :src="card.upFaceUrl" :size="20"></DpiImage>
|
||||
<div class="name">{{ card.upName }}</div>
|
||||
</a>
|
||||
<div
|
||||
v-else
|
||||
class="description"
|
||||
>
|
||||
<div v-else class="description">
|
||||
{{ card.description }}
|
||||
</div>
|
||||
</div>
|
||||
@ -72,15 +65,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
VLoading,
|
||||
VEmpty,
|
||||
VIcon,
|
||||
VButton,
|
||||
TextBox,
|
||||
DpiImage,
|
||||
ScrollTrigger,
|
||||
} from '@/ui'
|
||||
import { VLoading, VEmpty, VIcon, VButton, TextBox, DpiImage, ScrollTrigger } from '@/ui'
|
||||
import { formatDate, formatDuration } from '@/core/utils/formatters'
|
||||
import { getUID } from '@/core/utils'
|
||||
import { getJsonWithCredentials } from '@/core/ajax'
|
||||
@ -131,8 +116,12 @@ async function searchAllList() {
|
||||
}
|
||||
try {
|
||||
this.loading = true
|
||||
const jsonCurrent = await getJsonWithCredentials(`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=0&tid=0&platform=web`)
|
||||
const jsonAll = await getJsonWithCredentials(`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=1&tid=0&platform=web`)
|
||||
const jsonCurrent = await getJsonWithCredentials(
|
||||
`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=0&tid=0&platform=web`,
|
||||
)
|
||||
const jsonAll = await getJsonWithCredentials(
|
||||
`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${this.folder.id}&pn=${this.searchPage}&ps=${MaxPageSize}&keyword=${this.search}&order=mtime&type=1&tid=0&platform=web`,
|
||||
)
|
||||
if (jsonCurrent.code !== 0 && jsonAll.code !== 0) {
|
||||
return
|
||||
}
|
||||
@ -222,8 +211,7 @@ export default Vue.extend({
|
||||
this.hasMoreSearchPage = true
|
||||
this.searchPage = 1
|
||||
this.filteredCards = (this.cards as FavoritesItemInfo[]).filter(
|
||||
it => it.title.toLowerCase().includes(keyword)
|
||||
|| it.upName.toLowerCase().includes(keyword),
|
||||
it => it.title.toLowerCase().includes(keyword) || it.upName.toLowerCase().includes(keyword),
|
||||
)
|
||||
},
|
||||
},
|
||||
@ -238,9 +226,7 @@ export default Vue.extend({
|
||||
// 超过最后一页后返回空数组
|
||||
return []
|
||||
}
|
||||
return json.data.medias
|
||||
.filter(favoriteItemFilter)
|
||||
.map(favoriteItemMapper)
|
||||
return json.data.medias.filter(favoriteItemFilter).map(favoriteItemMapper)
|
||||
},
|
||||
async changeList() {
|
||||
if (this.folder.id === 0) {
|
||||
@ -284,8 +270,8 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "../popup";
|
||||
@import 'common';
|
||||
@import '../popup';
|
||||
|
||||
.custom-navbar .favorites-list {
|
||||
width: 380px;
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<div class="navbar-feeds">
|
||||
<TabControl
|
||||
ref="tabControl"
|
||||
:tabs="tabs"
|
||||
more-link="https://t.bilibili.com/"
|
||||
>
|
||||
<TabControl ref="tabControl" :tabs="tabs" more-link="https://t.bilibili.com/">
|
||||
<template #more-link>
|
||||
所有动态
|
||||
<VIcon icon="feeds" :size="18"></VIcon>
|
||||
@ -13,10 +9,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
TabControl,
|
||||
VIcon,
|
||||
} from '@/ui'
|
||||
import { TabControl, VIcon } from '@/ui'
|
||||
import { feedsCardTypes } from '@/components/feeds/api'
|
||||
import { getNotifyCount } from '@/components/feeds/notify'
|
||||
import { popperMixin } from '../mixins'
|
||||
@ -61,7 +54,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "../popup";
|
||||
@import '../popup';
|
||||
|
||||
.navbar-feeds {
|
||||
width: 380px;
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<VLoading v-if="loading"></VLoading>
|
||||
<VEmpty v-else-if="!loading && cards.length === 0"></VEmpty>
|
||||
<transition-group name="cards" tag="div" class="live-feeds-content">
|
||||
<a
|
||||
v-for="c of cards"
|
||||
:key="c.id"
|
||||
class="live-card"
|
||||
target="_blank"
|
||||
:href="c.url"
|
||||
>
|
||||
<a v-for="c of cards" :key="c.id" class="live-card" target="_blank" :href="c.url">
|
||||
<div class="face-container">
|
||||
<DpiImage class="face" :size="48" :src="c.upFaceUrl"></DpiImage>
|
||||
</div>
|
||||
@ -22,11 +16,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
VLoading,
|
||||
VEmpty,
|
||||
DpiImage,
|
||||
} from '@/ui'
|
||||
import { VLoading, VEmpty, DpiImage } from '@/ui'
|
||||
import { responsiveGetPages, getJsonWithCredentials } from '@/core/ajax'
|
||||
import { LiveFeedItem } from './live-feed-item'
|
||||
|
||||
@ -57,9 +47,10 @@ export default Vue.extend({
|
||||
},
|
||||
async created() {
|
||||
const [responsive] = responsiveGetPages({
|
||||
api: page => getJsonWithCredentials(
|
||||
`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=24`,
|
||||
),
|
||||
api: page =>
|
||||
getJsonWithCredentials(
|
||||
`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=${page}&pagesize=24`,
|
||||
),
|
||||
getList: json => lodash.get(json, 'data.list', []),
|
||||
getTotal: json => lodash.get(json, 'data.results', 0),
|
||||
})
|
||||
@ -69,7 +60,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
.live-feeds {
|
||||
width: 100%;
|
||||
@include v-center();
|
||||
@ -132,7 +123,7 @@ export default Vue.extend({
|
||||
color: var(--theme-color);
|
||||
}
|
||||
.live-name {
|
||||
opacity: .75;
|
||||
opacity: 0.75;
|
||||
padding: 0 12px;
|
||||
@include single-line();
|
||||
line-height: normal;
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
* 返回一些假的番剧动态数据
|
||||
* (流下了没追番的泪水)
|
||||
*/
|
||||
export const getBangumiFeedsMockup = async () => JSON.parse(`{
|
||||
export const getBangumiFeedsMockup = async () =>
|
||||
JSON.parse(`{
|
||||
"code": 0,
|
||||
"msg": "",
|
||||
"message": "",
|
||||
|
||||
@ -7,11 +7,7 @@ import {
|
||||
import { descendingStringSort } from '@/core/utils/sort'
|
||||
import { logError } from '@/core/utils/log'
|
||||
import { setLatestID } from '@/components/feeds/notify'
|
||||
import {
|
||||
VLoading,
|
||||
VEmpty,
|
||||
ScrollTrigger,
|
||||
} from '@/ui'
|
||||
import { VLoading, VEmpty, ScrollTrigger } from '@/ui'
|
||||
|
||||
/**
|
||||
* 获取用于支持顶栏动态无限滚动的Vue Mixin
|
||||
@ -21,7 +17,8 @@ import {
|
||||
export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
|
||||
type: FeedsCardType,
|
||||
jsonMapper: (obj: RawItem) => MappedItem,
|
||||
) => (Vue.extend({
|
||||
) =>
|
||||
Vue.extend({
|
||||
components: {
|
||||
VLoading,
|
||||
VEmpty,
|
||||
@ -44,7 +41,7 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
|
||||
const cards = this.sortedCards as MappedItem[]
|
||||
if (cards.length > 0) {
|
||||
setLatestID(cards[0].id)
|
||||
// console.log('setLatestID', cards[0].id)
|
||||
// console.log('setLatestID', cards[0].id)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -77,7 +74,8 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
|
||||
this.hasMorePage = false
|
||||
return
|
||||
}
|
||||
this.hasMorePage = lastCardID === 0 ? true : Boolean(lodash.get(json, 'data.has_more', true))
|
||||
this.hasMorePage =
|
||||
lastCardID === 0 ? true : Boolean(lodash.get(json, 'data.has_more', true))
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
} finally {
|
||||
@ -85,4 +83,4 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
|
||||
}
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
@ -6,10 +6,7 @@
|
||||
<TextBox v-model="search" placeholder="搜索" linear></TextBox>
|
||||
</div>
|
||||
<div class="operations">
|
||||
<div
|
||||
class="operation"
|
||||
@click="toggleHistoryPause"
|
||||
>
|
||||
<div class="operation" @click="toggleHistoryPause">
|
||||
<VButton v-if="!paused" title="暂停记录历史" round>
|
||||
<VIcon icon="mdi-pause" :size="14"></VIcon>
|
||||
</VButton>
|
||||
@ -17,11 +14,7 @@
|
||||
<VIcon icon="mdi-play" :size="14"></VIcon>
|
||||
</VButton>
|
||||
</div>
|
||||
<a
|
||||
class="operation"
|
||||
target="_blank"
|
||||
href="https://www.bilibili.com/account/history"
|
||||
>
|
||||
<a class="operation" target="_blank" href="https://www.bilibili.com/account/history">
|
||||
<VButton title="查看更多" round>
|
||||
<VIcon icon="mdi-dots-horizontal" :size="18"></VIcon>
|
||||
</VButton>
|
||||
@ -29,9 +22,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-row">
|
||||
<div class="row-title">
|
||||
过滤:
|
||||
</div>
|
||||
<div class="row-title">过滤:</div>
|
||||
<div class="type-filters">
|
||||
<div v-for="t of types" :key="t.name" class="type-filter">
|
||||
<VButton
|
||||
@ -55,11 +46,7 @@
|
||||
<div class="time-group-name">
|
||||
{{ g.name }}
|
||||
</div>
|
||||
<transition-group
|
||||
name="time-group"
|
||||
tag="div"
|
||||
class="time-group-items"
|
||||
>
|
||||
<transition-group name="time-group" tag="div" class="time-group-items">
|
||||
<div v-for="h of g.items" :key="h.id" class="time-group-item">
|
||||
<a class="cover-container" target="_blank" :href="h.url">
|
||||
<DpiImage
|
||||
@ -73,26 +60,21 @@
|
||||
class="progress"
|
||||
:style="{ width: h.progress * 100 + '%' }"
|
||||
></div>
|
||||
<div
|
||||
v-if="h.progressText"
|
||||
class="floating progress-number"
|
||||
>{{ h.progress >= 1 ? '已看完' : h.progressText }}</div>
|
||||
<div v-if="h.progressText" class="floating progress-number">
|
||||
{{ h.progress >= 1 ? '已看完' : h.progressText }}
|
||||
</div>
|
||||
<div
|
||||
v-if="h.liveStatus !== undefined"
|
||||
class="floating duration live-status"
|
||||
:class="{ on: h.liveStatus === 1 }"
|
||||
>{{ h.liveStatus === 1 ? '直播中': '未开播' }}</div>
|
||||
<div
|
||||
v-if="h.durationText"
|
||||
class="floating duration"
|
||||
>{{ h.durationText }}</div>
|
||||
>
|
||||
{{ h.liveStatus === 1 ? '直播中' : '未开播' }}
|
||||
</div>
|
||||
<div v-if="h.durationText" class="floating duration">{{ h.durationText }}</div>
|
||||
</a>
|
||||
<a
|
||||
class="title"
|
||||
target="_blank"
|
||||
:href="h.url"
|
||||
:title="h.title"
|
||||
>{{ h.title || h.upName + '的直播间' }}</a>
|
||||
<a class="title" target="_blank" :href="h.url" :title="h.title">{{
|
||||
h.title || h.upName + '的直播间'
|
||||
}}</a>
|
||||
<a
|
||||
class="up"
|
||||
target="_blank"
|
||||
@ -107,11 +89,7 @@
|
||||
></DpiImage>
|
||||
<div class="up-name">{{ h.upName }}</div>
|
||||
</a>
|
||||
<div
|
||||
v-if="h.timeText"
|
||||
class="time"
|
||||
:title="new Date(h.viewAt).toLocaleString()"
|
||||
>
|
||||
<div v-if="h.timeText" class="time" :title="new Date(h.viewAt).toLocaleString()">
|
||||
{{ h.timeText }}
|
||||
</div>
|
||||
</div>
|
||||
@ -130,19 +108,9 @@
|
||||
import { bilibiliApi, getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
||||
import { formData, getCsrf } from '@/core/utils'
|
||||
import { descendingSort } from '@/core/utils/sort'
|
||||
import {
|
||||
VButton,
|
||||
VIcon,
|
||||
TextBox,
|
||||
VLoading,
|
||||
VEmpty,
|
||||
ScrollTrigger,
|
||||
DpiImage,
|
||||
} from '@/ui'
|
||||
import { VButton, VIcon, TextBox, VLoading, VEmpty, ScrollTrigger, DpiImage } from '@/ui'
|
||||
import { popperMixin } from '../mixins'
|
||||
import {
|
||||
types, TypeFilter, HistoryItem, getHistoryItems, group,
|
||||
} from './types'
|
||||
import { types, TypeFilter, HistoryItem, getHistoryItems, group } from './types'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
@ -170,10 +138,10 @@ export default Vue.extend({
|
||||
computed: {
|
||||
canNextPage() {
|
||||
return (
|
||||
this.search === ''
|
||||
&& !this.loading
|
||||
&& this.hasMorePage
|
||||
&& this.types.every((t: TypeFilter) => t.checked)
|
||||
this.search === '' &&
|
||||
!this.loading &&
|
||||
this.hasMorePage &&
|
||||
this.types.every((t: TypeFilter) => t.checked)
|
||||
)
|
||||
},
|
||||
},
|
||||
@ -184,10 +152,7 @@ export default Vue.extend({
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
await Promise.all([
|
||||
this.nextPage(),
|
||||
this.updateHistoryPauseState(),
|
||||
])
|
||||
await Promise.all([this.nextPage(), this.updateHistoryPauseState()])
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
@ -202,8 +167,8 @@ export default Vue.extend({
|
||||
return false
|
||||
}
|
||||
if (
|
||||
!item.title.toLowerCase().includes(this.search.toLowerCase())
|
||||
&& !item.upName.toLowerCase().includes(this.search.toLowerCase())
|
||||
!item.title.toLowerCase().includes(this.search.toLowerCase()) &&
|
||||
!item.upName.toLowerCase().includes(this.search.toLowerCase())
|
||||
) {
|
||||
return false
|
||||
}
|
||||
@ -215,9 +180,7 @@ export default Vue.extend({
|
||||
async nextPage() {
|
||||
const items = await getHistoryItems(this.viewTime)
|
||||
const cards: HistoryItem[] = lodash.uniqBy(
|
||||
this.cards
|
||||
.concat(items)
|
||||
.sort(descendingSort((item: HistoryItem) => item.viewAt)),
|
||||
this.cards.concat(items).sort(descendingSort((item: HistoryItem) => item.viewAt)),
|
||||
item => item.id,
|
||||
)
|
||||
this.cards = cards
|
||||
@ -228,7 +191,9 @@ export default Vue.extend({
|
||||
this.hasMorePage = cards.length !== 0
|
||||
},
|
||||
async updateHistoryPauseState() {
|
||||
const result = await bilibiliApi(getJsonWithCredentials('https://api.bilibili.com/x/v2/history/shadow'))
|
||||
const result = await bilibiliApi(
|
||||
getJsonWithCredentials('https://api.bilibili.com/x/v2/history/shadow'),
|
||||
)
|
||||
/*
|
||||
result == true: 暂停
|
||||
result == {}: 没暂停
|
||||
@ -254,8 +219,8 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "../popup";
|
||||
@import 'common';
|
||||
@import '../popup';
|
||||
|
||||
.custom-navbar-history-list {
|
||||
width: 350px;
|
||||
|
||||
@ -95,9 +95,18 @@ const formatTime = (date: Date) => {
|
||||
const { yesterday } = getTimeData()
|
||||
const timestamp = Number(date)
|
||||
if (timestamp >= yesterday) {
|
||||
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
||||
return `${date.getHours().toString().padStart(2, '0')}:${date
|
||||
.getMinutes()
|
||||
.toString()
|
||||
.padStart(2, '0')}`
|
||||
}
|
||||
return `${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
||||
return `${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
|
||||
.getDate()
|
||||
.toString()
|
||||
.padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date
|
||||
.getMinutes()
|
||||
.toString()
|
||||
.padStart(2, '0')}`
|
||||
}
|
||||
const parseHistoryItem = (item: any): HistoryItem => {
|
||||
if (item.history.business === 'article') {
|
||||
@ -110,7 +119,7 @@ const parseHistoryItem = (item: any): HistoryItem => {
|
||||
oid, // 直播 房间号 / 专栏 cv 号
|
||||
} = item.history
|
||||
const progressParam = item.progress > 0 ? `t=${item.progress}` : 't=0'
|
||||
const progress = item.progress === -1 ? 1 : (item.progress / item.duration)
|
||||
const progress = item.progress === -1 ? 1 : item.progress / item.duration
|
||||
const https = (url: string) => url.replace('http:', 'https:')
|
||||
const time = new Date(item.view_at * 1000)
|
||||
const cover = (() => {
|
||||
|
||||
@ -9,10 +9,7 @@
|
||||
>
|
||||
<a :href="data.link" target="_blank">
|
||||
<svg aria-hidden="true">
|
||||
<use
|
||||
:href="'#header-icon-' + data.icon"
|
||||
:xlink:href="'#header-icon-' + data.icon"
|
||||
/>
|
||||
<use :href="'#header-icon-' + data.icon" :xlink:href="'#header-icon-' + data.icon" />
|
||||
</svg>
|
||||
<div class="name">{{ name }}</div>
|
||||
<span class="count">
|
||||
@ -26,7 +23,8 @@
|
||||
class="sub-region"
|
||||
:href="url"
|
||||
target="_blank"
|
||||
>{{ regionName }}</a>
|
||||
>{{ regionName }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -94,8 +92,8 @@ export default Vue.extend({
|
||||
// 3. https://stackoverflow.com/a/33899301/13860169
|
||||
flex-direction: row;
|
||||
writing-mode: vertical-lr;
|
||||
&>* {
|
||||
writing-mode: horizontal-tb
|
||||
& > * {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<iframe
|
||||
:src="item.src"
|
||||
frameborder="0"
|
||||
:width="item.width"
|
||||
:height="item.height"
|
||||
></iframe>
|
||||
<iframe :src="item.src" frameborder="0" :width="item.width" :height="item.height"></iframe>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import { defineComponentMetadata, defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
|
||||
import {
|
||||
defineComponentMetadata,
|
||||
defineOptionsMetadata,
|
||||
OptionsOfMetadata,
|
||||
} from '@/components/define'
|
||||
import { LaunchBarActionProvider } from '@/components/launch-bar/launch-bar-action'
|
||||
import { urlInclude, urlExclude } from './urls'
|
||||
import { entry } from './entry'
|
||||
@ -77,10 +81,7 @@ export const component = defineComponentMetadata({
|
||||
name: 'customNavbar',
|
||||
displayName: '自定义顶栏',
|
||||
entry,
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.general,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.general],
|
||||
options,
|
||||
urlInclude,
|
||||
urlExclude,
|
||||
@ -110,15 +111,17 @@ export const component = defineComponentMetadata({
|
||||
addData('launchBar.actions', (providers: LaunchBarActionProvider[]) => {
|
||||
providers.push({
|
||||
name: 'navbarSettings',
|
||||
getActions: async () => [{
|
||||
name: '自定义顶栏设置',
|
||||
description: 'Custom Navbar Settings',
|
||||
icon: 'mdi-sort',
|
||||
action: async () => {
|
||||
const { toggleNavbarSettings } = await import('./settings/vm')
|
||||
toggleNavbarSettings()
|
||||
getActions: async () => [
|
||||
{
|
||||
name: '自定义顶栏设置',
|
||||
description: 'Custom Navbar Settings',
|
||||
icon: 'mdi-sort',
|
||||
action: async () => {
|
||||
const { toggleNavbarSettings } = await import('./settings/vm')
|
||||
toggleNavbarSettings()
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@ -37,17 +37,12 @@ export default Vue.extend({
|
||||
this.seasonLogoUrl = ''
|
||||
return
|
||||
}
|
||||
const json = await getJson(
|
||||
'https://api.bilibili.com/x/web-show/page/header?resource_id=1',
|
||||
)
|
||||
const json = await getJson('https://api.bilibili.com/x/web-show/page/header?resource_id=1')
|
||||
if (json.code !== 0) {
|
||||
this.seasonLogoUrl = ''
|
||||
return
|
||||
}
|
||||
this.seasonLogoUrl = lodash.get(json, 'data.litpic', '').replace(
|
||||
'http:',
|
||||
'https:',
|
||||
)
|
||||
this.seasonLogoUrl = lodash.get(json, 'data.litpic', '').replace('http:', 'https:')
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
:href="e.href"
|
||||
:data-count="e.count || null"
|
||||
@click="clearCount(e)"
|
||||
>{{ e.name }}</a>
|
||||
>{{ e.name }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -99,9 +100,7 @@ export default Vue.extend({
|
||||
return
|
||||
}
|
||||
const [mainJson, messageJson] = await Promise.all([
|
||||
getJsonWithCredentials(
|
||||
'https://api.bilibili.com/x/msgfeed/unread',
|
||||
),
|
||||
getJsonWithCredentials('https://api.bilibili.com/x/msgfeed/unread'),
|
||||
getJsonWithCredentials(
|
||||
'https://api.vc.bilibili.com/session_svr/v1/session_svr/single_unread',
|
||||
),
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
<template>
|
||||
<div class="ranking-popup" role="list">
|
||||
<div v-for="e of entries" :key="e.name" class="ranking-entry" role="listitem">
|
||||
<a
|
||||
target="_blank"
|
||||
:href="e.href"
|
||||
>{{ e.name }}</a>
|
||||
<a target="_blank" :href="e.href">{{ e.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -17,7 +17,7 @@ export default Vue.extend({
|
||||
// transparent mode / no fill
|
||||
.launch-bar {
|
||||
--color: var(--custom-navbar-foreground);
|
||||
background-color: #000A;
|
||||
background-color: #000a;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s ease-out;
|
||||
padding: 2px 6px;
|
||||
|
||||
@ -13,11 +13,7 @@
|
||||
<script lang="ts">
|
||||
import { getUID } from '@/core/utils'
|
||||
import { VIcon, VButton } from '@/ui'
|
||||
import {
|
||||
setTriggerElement,
|
||||
loadNavbarSettings,
|
||||
toggleNavbarSettings,
|
||||
} from './vm'
|
||||
import { setTriggerElement, loadNavbarSettings, toggleNavbarSettings } from './vm'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
|
||||
@ -9,9 +9,7 @@
|
||||
>
|
||||
<div class="navbar-settings-header">
|
||||
<VIcon class="title-icon" icon="mdi-sort" :size="24"></VIcon>
|
||||
<div class="title">
|
||||
顶栏布局设置
|
||||
</div>
|
||||
<div class="title">顶栏布局设置</div>
|
||||
<div class="grow"></div>
|
||||
<div class="close" @click="open = false">
|
||||
<VIcon icon="close" :size="18"></VIcon>
|
||||
@ -19,9 +17,7 @@
|
||||
</div>
|
||||
<div class="navbar-settings-content">
|
||||
<div class="navbar-settings-section">
|
||||
<div class="navbar-settings-section-title">
|
||||
边缘间距
|
||||
</div>
|
||||
<div class="navbar-settings-section-title">边缘间距</div>
|
||||
<div class="navbar-settings-section-description">
|
||||
设定两侧边缘处的间距, 单位为百分比, 100%为整个顶栏的宽度.
|
||||
<br />空间不足时, 实际呈现的间距会自动缩小.
|
||||
@ -32,18 +28,12 @@
|
||||
@mouseout="peekPadding(false)"
|
||||
>
|
||||
<VSlider v-model="padding" :min="0" :max="40" :step="0.5"></VSlider>
|
||||
<div class="padding-value">
|
||||
{{ padding.toFixed(1) }}%
|
||||
</div>
|
||||
<div class="padding-value">{{ padding.toFixed(1) }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navbar-settings-section">
|
||||
<div class="navbar-settings-section-title">
|
||||
元素呈现
|
||||
</div>
|
||||
<div
|
||||
class="navbar-settings-section-description"
|
||||
>
|
||||
<div class="navbar-settings-section-title">元素呈现</div>
|
||||
<div class="navbar-settings-section-description">
|
||||
按住并拖动可以调整顺序, 点击眼睛图标可以切换隐藏/显示.
|
||||
</div>
|
||||
<VLoading v-if="!loaded" />
|
||||
@ -67,11 +57,7 @@
|
||||
<div class="toggle-visible">
|
||||
<VIcon
|
||||
:size="18"
|
||||
:icon="
|
||||
item.hidden
|
||||
? 'mdi-eye-off-outline'
|
||||
: 'mdi-eye-outline'
|
||||
"
|
||||
:icon="item.hidden ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
|
||||
@click="toggleVisible(item)"
|
||||
></VIcon>
|
||||
</div>
|
||||
@ -83,26 +69,20 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { SortableEvent } from 'sortablejs'
|
||||
import {
|
||||
VPopup,
|
||||
VIcon,
|
||||
VSlider,
|
||||
VLoading,
|
||||
} from '@/ui'
|
||||
import { VPopup, VIcon, VSlider, VLoading } from '@/ui'
|
||||
import { addComponentListener } from '@/core/settings'
|
||||
import { dqa } from '@/core/utils'
|
||||
import { SortableJSLibrary } from '@/core/runtime-library'
|
||||
import { getData } from '@/plugins/data'
|
||||
import {
|
||||
CustomNavbarItem,
|
||||
CustomNavbarRenderedItems,
|
||||
} from '../custom-navbar-item'
|
||||
import { CustomNavbarItem, CustomNavbarRenderedItems } from '../custom-navbar-item'
|
||||
import { checkSequentialOrder, sortItems } from './orders'
|
||||
|
||||
const { navbarOptions } = CustomNavbarItem
|
||||
const [rendered] = getData(CustomNavbarRenderedItems) as [{
|
||||
items: CustomNavbarItem[]
|
||||
}]
|
||||
const [rendered] = getData(CustomNavbarRenderedItems) as [
|
||||
{
|
||||
items: CustomNavbarItem[]
|
||||
},
|
||||
]
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
VPopup,
|
||||
@ -166,9 +146,9 @@ export default Vue.extend({
|
||||
const container = this.$refs.navbarSortList as HTMLElement
|
||||
const element = e.item
|
||||
console.log(`${element.getAttribute('data-name')} ${e.oldIndex}->${e.newIndex}`)
|
||||
const ordersMap = Object.fromEntries([...container.children].map((el, index) => (
|
||||
[el.getAttribute('data-name') as string, index]
|
||||
)))
|
||||
const ordersMap = Object.fromEntries(
|
||||
[...container.children].map((el, index) => [el.getAttribute('data-name') as string, index]),
|
||||
)
|
||||
this.rendered.items = sortItems(rendered.items, ordersMap)
|
||||
},
|
||||
toggleVisible(item: CustomNavbarItem) {
|
||||
@ -186,7 +166,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
.custom-navbar-settings {
|
||||
@include popup();
|
||||
width: 400px;
|
||||
|
||||
@ -7,7 +7,7 @@ const regenerateOrder = (items: CustomNavbarItem[]) => {
|
||||
}
|
||||
item.order = index
|
||||
})
|
||||
const orderMap = Object.fromEntries(items.map(it => ([it.name, it.order])))
|
||||
const orderMap = Object.fromEntries(items.map(it => [it.name, it.order]))
|
||||
CustomNavbarItem.navbarOptions.order = orderMap
|
||||
}
|
||||
export const checkSequentialOrder = (items: CustomNavbarItem[]) => {
|
||||
|
||||
@ -38,7 +38,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "../popup";
|
||||
@import '../popup';
|
||||
|
||||
.navbar-subscriptions {
|
||||
width: 380px;
|
||||
|
||||
@ -17,27 +17,18 @@
|
||||
<div class="card-info">
|
||||
<h1 class="title" :title="card.title">{{ card.title }}</h1>
|
||||
<div class="progress-row">
|
||||
<div
|
||||
v-if="card.status"
|
||||
class="status"
|
||||
:class="'status-' + card.status"
|
||||
>{{ card.statusText }}</div>
|
||||
<div v-if="card.status" class="status" :class="'status-' + card.status">
|
||||
{{ card.statusText }}
|
||||
</div>
|
||||
<div
|
||||
v-if="card.progress"
|
||||
class="progress"
|
||||
:title="card.progress + ' | ' + card.latest"
|
||||
>{{ card.progress }} | {{ card.latest }}</div>
|
||||
<div
|
||||
v-else
|
||||
class="progress"
|
||||
:title="card.latest"
|
||||
>{{ card.latest }}</div>
|
||||
<a
|
||||
class="info"
|
||||
:href="card.mediaUrl"
|
||||
target="_blank"
|
||||
title="详细信息"
|
||||
>
|
||||
{{ card.progress }} | {{ card.latest }}
|
||||
</div>
|
||||
<div v-else class="progress" :title="card.latest">{{ card.latest }}</div>
|
||||
<a class="info" :href="card.mediaUrl" target="_blank" title="详细信息">
|
||||
<VIcon icon="mdi-information-outline" :size="16"></VIcon>
|
||||
</a>
|
||||
</div>
|
||||
@ -52,13 +43,7 @@
|
||||
<script lang="ts">
|
||||
import { getUID } from '@/core/utils'
|
||||
import { logError } from '@/core/utils/log'
|
||||
import {
|
||||
DpiImage,
|
||||
VLoading,
|
||||
VEmpty,
|
||||
VIcon,
|
||||
ScrollTrigger,
|
||||
} from '@/ui'
|
||||
import { DpiImage, VLoading, VEmpty, VIcon, ScrollTrigger } from '@/ui'
|
||||
import { getJsonWithCredentials } from '@/core/ajax'
|
||||
import { SubscriptionTypes } from './subscriptions'
|
||||
|
||||
@ -129,22 +114,24 @@ export default Vue.extend({
|
||||
logError(`加载订阅信息失败: ${json.message}`)
|
||||
return
|
||||
}
|
||||
const cards = lodash.uniqBy(
|
||||
(this.cards as any[]).concat(
|
||||
(lodash.get(json, 'data.list') as any[]).map(item => ({
|
||||
title: item.title,
|
||||
coverUrl: item.square_cover.replace('http:', 'https:'),
|
||||
latest: item.new_ep.index_show,
|
||||
progress: item.progress,
|
||||
id: item.season_id,
|
||||
status: item.follow_status,
|
||||
statusText: getStatusText(item.follow_status),
|
||||
playUrl: `https://www.bilibili.com/bangumi/play/ss${item.season_id}`,
|
||||
mediaUrl: `https://www.bilibili.com/bangumi/media/md${item.media_id}`,
|
||||
})),
|
||||
),
|
||||
card => card.id,
|
||||
).sort(subscriptionSorter)
|
||||
const cards = lodash
|
||||
.uniqBy(
|
||||
(this.cards as any[]).concat(
|
||||
(lodash.get(json, 'data.list') as any[]).map(item => ({
|
||||
title: item.title,
|
||||
coverUrl: item.square_cover.replace('http:', 'https:'),
|
||||
latest: item.new_ep.index_show,
|
||||
progress: item.progress,
|
||||
id: item.season_id,
|
||||
status: item.follow_status,
|
||||
statusText: getStatusText(item.follow_status),
|
||||
playUrl: `https://www.bilibili.com/bangumi/play/ss${item.season_id}`,
|
||||
mediaUrl: `https://www.bilibili.com/bangumi/media/md${item.media_id}`,
|
||||
})),
|
||||
),
|
||||
card => card.id,
|
||||
)
|
||||
.sort(subscriptionSorter)
|
||||
this.page++
|
||||
this.cards = cards
|
||||
this.hasMorePage = lodash.get(json, 'data.total', 0) > this.cards.length
|
||||
@ -157,7 +144,7 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.subscription-list {
|
||||
width: 100%;
|
||||
|
||||
@ -12,7 +12,10 @@ export const checkTransparentFill = async (vm: {
|
||||
return
|
||||
}
|
||||
sq(
|
||||
() => dqa('.animated-banner video, .banner-img img, #banner_link, .international-header .bili-banner, .bili-header__banner'),
|
||||
() =>
|
||||
dqa(
|
||||
'.animated-banner video, .banner-img img, #banner_link, .international-header .bili-banner, .bili-header__banner',
|
||||
),
|
||||
banners => {
|
||||
if (banners.length === 0) {
|
||||
return false
|
||||
@ -35,11 +38,15 @@ export const checkTransparentFill = async (vm: {
|
||||
if (banner.length === 0) {
|
||||
return
|
||||
}
|
||||
addComponentListener('customNavbar.transparent', value => {
|
||||
if (!getComponentSettings('hideBanner').enabled) {
|
||||
vm.toggleStyle(value, 'transparent')
|
||||
}
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'customNavbar.transparent',
|
||||
value => {
|
||||
if (!getComponentSettings('hideBanner').enabled) {
|
||||
vm.toggleStyle(value, 'transparent')
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
addComponentListener('hideBanner', value => {
|
||||
if (getComponentSettings('customNavbar').options.transparent) {
|
||||
vm.toggleStyle(!value, 'transparent')
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="navbar-upload">
|
||||
<VIcon icon="upload" :size="18"></VIcon>
|
||||
<div class="navbar-upload-name">
|
||||
投稿
|
||||
</div>
|
||||
<div class="navbar-upload-name">投稿</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
||||
@ -1,34 +1,21 @@
|
||||
<template>
|
||||
<div role="list" class="upload-popup">
|
||||
<div role="listitem">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://member.bilibili.com/platform/upload/text/apply"
|
||||
>专栏投稿</a>
|
||||
<a target="_blank" href="https://member.bilibili.com/platform/upload/text/apply">专栏投稿</a>
|
||||
</div>
|
||||
<div role="listitem">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://member.bilibili.com/platform/upload/audio/frame"
|
||||
>音频投稿</a>
|
||||
<a target="_blank" href="https://member.bilibili.com/platform/upload/audio/frame">音频投稿</a>
|
||||
</div>
|
||||
<div role="listitem">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://member.bilibili.com/platform/upload/sticker"
|
||||
>贴纸投稿</a>
|
||||
<a target="_blank" href="https://member.bilibili.com/platform/upload/sticker">贴纸投稿</a>
|
||||
</div>
|
||||
<div role="listitem">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://member.bilibili.com/platform/upload/video/frame"
|
||||
>视频投稿</a>
|
||||
<a target="_blank" href="https://member.bilibili.com/platform/upload/video/frame">视频投稿</a>
|
||||
</div>
|
||||
<div role="listitem">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://member.bilibili.com/platform/upload-manager/article"
|
||||
>投稿管理</a>
|
||||
<a target="_blank" href="https://member.bilibili.com/platform/upload-manager/article"
|
||||
>投稿管理</a
|
||||
>
|
||||
</div>
|
||||
<div role="listitem">
|
||||
<a target="_blank" href="https://member.bilibili.com/platform/home">创作中心</a>
|
||||
@ -43,7 +30,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../nav-link";
|
||||
@import '../nav-link';
|
||||
.upload-popup {
|
||||
width: max-content;
|
||||
a {
|
||||
|
||||
@ -1,16 +1,10 @@
|
||||
<template>
|
||||
<div class="user-info-panel">
|
||||
<div v-if="isLogin && userInfo.isLogin === true" class="logged-in">
|
||||
<a
|
||||
class="name"
|
||||
target="_blank"
|
||||
href="https://space.bilibili.com/"
|
||||
>{{ userInfo.uname }}</a>
|
||||
<a
|
||||
class="type"
|
||||
target="_blank"
|
||||
href="https://account.bilibili.com/account/big"
|
||||
>{{ userType }}</a>
|
||||
<a class="name" target="_blank" href="https://space.bilibili.com/">{{ userInfo.uname }}</a>
|
||||
<a class="type" target="_blank" href="https://account.bilibili.com/account/big">{{
|
||||
userType
|
||||
}}</a>
|
||||
<div v-if="userInfo.vipStatus === 1 && userInfo.vipType === 2" class="privileges row">
|
||||
<div
|
||||
class="b-coin"
|
||||
@ -43,15 +37,11 @@
|
||||
:size="30"
|
||||
class="level-icon plus"
|
||||
/>
|
||||
<VIcon
|
||||
v-else
|
||||
:icon="'lv' + userInfo.level_info.current_level"
|
||||
class="level-icon"
|
||||
/>
|
||||
<VIcon v-else :icon="'lv' + userInfo.level_info.current_level" class="level-icon" />
|
||||
</a>
|
||||
<span
|
||||
class="level-progress-label"
|
||||
>{{ userInfo.level_info.current_exp }} / {{ userInfo.level_info.next_exp }}</span>
|
||||
<span class="level-progress-label"
|
||||
>{{ userInfo.level_info.current_exp }} / {{ userInfo.level_info.next_exp }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="level-progress separator">
|
||||
<div class="level-progress-thumb" :style="levelProgressStyle"></div>
|
||||
@ -77,21 +67,11 @@
|
||||
<VIcon v-if="userInfo.email_verified" icon="ok" :size="18"></VIcon>
|
||||
<VIcon v-else icon="cancel" :size="18"></VIcon>
|
||||
</a>
|
||||
<a
|
||||
class="item"
|
||||
target="_blank"
|
||||
href="https://account.bilibili.com/site/coin"
|
||||
title="硬币"
|
||||
>
|
||||
<a class="item" target="_blank" href="https://account.bilibili.com/site/coin" title="硬币">
|
||||
<VIcon icon="coin-outline" :size="20"></VIcon>
|
||||
<span>{{ userInfo.money }}</span>
|
||||
</a>
|
||||
<a
|
||||
class="item"
|
||||
target="_blank"
|
||||
href="https://pay.bilibili.com/bb_balance.html"
|
||||
title="B币"
|
||||
>
|
||||
<a class="item" target="_blank" href="https://pay.bilibili.com/bb_balance.html" title="B币">
|
||||
<VIcon icon="b-coin-outline" :size="20"></VIcon>
|
||||
<span>{{ userInfo.wallet.bcoin_balance }}</span>
|
||||
</a>
|
||||
@ -103,21 +83,24 @@
|
||||
:href="'https://space.bilibili.com/' + userInfo.mid + '/fans/follow'"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="stats-number">{{ stat.following | count }}</div>关注
|
||||
<div class="stats-number">{{ stat.following | count }}</div>
|
||||
关注
|
||||
</a>
|
||||
<a
|
||||
class="stats-item"
|
||||
:href="'https://space.bilibili.com/' + userInfo.mid + '/fans/fans'"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="stats-number">{{ stat.follower | count }}</div>粉丝
|
||||
<div class="stats-number">{{ stat.follower | count }}</div>
|
||||
粉丝
|
||||
</a>
|
||||
<a
|
||||
class="stats-item"
|
||||
:href="'https://space.bilibili.com/' + userInfo.mid + '/dynamic'"
|
||||
target="_blank"
|
||||
>
|
||||
<div class="stats-number">{{ stat.dynamic_count | count }}</div>动态
|
||||
<div class="stats-number">{{ stat.dynamic_count | count }}</div>
|
||||
动态
|
||||
</a>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
@ -159,25 +142,14 @@
|
||||
>
|
||||
<VIcon icon="course"></VIcon>我的课程
|
||||
</a>
|
||||
<div
|
||||
class="logout grey-button"
|
||||
@click="logout()"
|
||||
>
|
||||
退出登录
|
||||
</div>
|
||||
<div class="logout grey-button" @click="logout()">退出登录</div>
|
||||
</div>
|
||||
<div v-if="!isLogin" class="not-logged-in">
|
||||
<h1 class="welcome">
|
||||
欢迎来到 bilibili
|
||||
</h1>
|
||||
<a
|
||||
href="https://passport.bilibili.com/register/phone.html"
|
||||
class="signup grey-button"
|
||||
>注册</a>
|
||||
<a
|
||||
href="https://passport.bilibili.com/login"
|
||||
class="login theme-button"
|
||||
>登录</a>
|
||||
<h1 class="welcome">欢迎来到 bilibili</h1>
|
||||
<a href="https://passport.bilibili.com/register/phone.html" class="signup grey-button"
|
||||
>注册</a
|
||||
>
|
||||
<a href="https://passport.bilibili.com/login" class="login theme-button">登录</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -260,30 +232,18 @@ export default Vue.extend({
|
||||
async created() {
|
||||
const userInfo = await getUserInfo()
|
||||
this.userInfo = userInfo
|
||||
const json = await getJsonWithCredentials(
|
||||
'https://api.bilibili.com/x/web-interface/nav/stat',
|
||||
)
|
||||
const json = await getJsonWithCredentials('https://api.bilibili.com/x/web-interface/nav/stat')
|
||||
this.stat = json.data || {}
|
||||
if (this.isLogin && this.userInfo.vipType === 2) {
|
||||
// 年度大会员权益
|
||||
const privileges = await getJsonWithCredentials(
|
||||
'https://api.bilibili.com/x/vip/privilege/my',
|
||||
)
|
||||
const privileges = await getJsonWithCredentials('https://api.bilibili.com/x/vip/privilege/my')
|
||||
if (privileges.code === 0) {
|
||||
const bCoin = privileges.data.list.find(
|
||||
(it: { type: PrivilegeType }) => it.type === 1,
|
||||
)
|
||||
const bCoin = privileges.data.list.find((it: { type: PrivilegeType }) => it.type === 1)
|
||||
this.privileges.bCoin.received = bCoin.state === 1
|
||||
this.privileges.bCoin.expire = new Date(
|
||||
bCoin.expire_time * 1000,
|
||||
).toLocaleDateString()
|
||||
const coupons = privileges.data.list.find(
|
||||
(it: { type: PrivilegeType }) => it.type === 2,
|
||||
)
|
||||
this.privileges.bCoin.expire = new Date(bCoin.expire_time * 1000).toLocaleDateString()
|
||||
const coupons = privileges.data.list.find((it: { type: PrivilegeType }) => it.type === 2)
|
||||
this.privileges.coupons.received = coupons.state === 1
|
||||
this.privileges.coupons.expire = new Date(
|
||||
coupons.expire_time * 1000,
|
||||
).toLocaleDateString()
|
||||
this.privileges.coupons.expire = new Date(coupons.expire_time * 1000).toLocaleDateString()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -4,7 +4,11 @@
|
||||
<div class="search">
|
||||
<TextBox v-model="search" linear placeholder="搜索"></TextBox>
|
||||
</div>
|
||||
<a class="operation" target="_blank" href="https://www.bilibili.com/medialist/play/watchlater">
|
||||
<a
|
||||
class="operation"
|
||||
target="_blank"
|
||||
href="https://www.bilibili.com/medialist/play/watchlater"
|
||||
>
|
||||
<VButton class="round-button" title="播放全部" round>
|
||||
<VIcon icon="mdi-play" :size="18"></VIcon>
|
||||
</VButton>
|
||||
@ -17,39 +21,21 @@
|
||||
</div>
|
||||
<VLoading v-if="loading"></VLoading>
|
||||
<VEmpty v-else-if="!loading && cards.length === 0"></VEmpty>
|
||||
<transition-group
|
||||
v-else
|
||||
name="cards"
|
||||
tag="div"
|
||||
class="watchlater-list-content"
|
||||
>
|
||||
<div
|
||||
v-for="(card, index) of filteredCards"
|
||||
:key="card.aid"
|
||||
class="watchlater-card"
|
||||
>
|
||||
<transition-group v-else name="cards" tag="div" class="watchlater-list-content">
|
||||
<div v-for="(card, index) of filteredCards" :key="card.aid" class="watchlater-card">
|
||||
<a class="cover-container" target="_blank" :href="card.href">
|
||||
<DpiImage
|
||||
class="cover"
|
||||
:src="card.coverUrl"
|
||||
:size="{ width: 130, height: 85 }"
|
||||
></DpiImage>
|
||||
<div
|
||||
class="floating remove"
|
||||
title="移除"
|
||||
@click.prevent="remove(card.aid, index)"
|
||||
>
|
||||
<div class="floating remove" title="移除" @click.prevent="remove(card.aid, index)">
|
||||
<VIcon icon="mdi-close" :size="16"></VIcon>
|
||||
</div>
|
||||
<div class="floating duration">{{ card.durationText }}</div>
|
||||
<div v-if="card.complete" class="floating viewed">已观看</div>
|
||||
</a>
|
||||
<a
|
||||
class="title"
|
||||
target="_blank"
|
||||
:href="card.href"
|
||||
:title="card.title"
|
||||
>{{ card.title }}</a>
|
||||
<a class="title" target="_blank" :href="card.href" :title="card.title">{{ card.title }}</a>
|
||||
<a
|
||||
class="up"
|
||||
target="_blank"
|
||||
@ -72,14 +58,7 @@ import {
|
||||
RawWatchlaterItem,
|
||||
toggleWatchlater,
|
||||
} from '@/components/video/watchlater'
|
||||
import {
|
||||
VLoading,
|
||||
VEmpty,
|
||||
TextBox,
|
||||
VButton,
|
||||
VIcon,
|
||||
DpiImage,
|
||||
} from '@/ui'
|
||||
import { VLoading, VEmpty, TextBox, VButton, VIcon, DpiImage } from '@/ui'
|
||||
import { popperMixin } from '../mixins'
|
||||
|
||||
interface WatchlaterCard {
|
||||
@ -191,17 +170,17 @@ export default Vue.extend({
|
||||
const search = this.search.toLowerCase()
|
||||
const cardsList = this.$el.querySelector('.watchlater-list-content') as HTMLElement
|
||||
cardsList.scrollTo(0, 0)
|
||||
this.filteredCards = (this.cards as WatchlaterCard[]).filter(card => (
|
||||
card.title.toLowerCase().includes(search)
|
||||
|| card.upName.toLowerCase().includes(search)
|
||||
))
|
||||
this.filteredCards = (this.cards as WatchlaterCard[]).filter(
|
||||
card =>
|
||||
card.title.toLowerCase().includes(search) || card.upName.toLowerCase().includes(search),
|
||||
)
|
||||
}, 100),
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "../popup";
|
||||
@import 'common';
|
||||
@import '../popup';
|
||||
|
||||
.custom-navbar .watchlater-list {
|
||||
@include navbar-popup-height();
|
||||
|
||||
@ -22,10 +22,7 @@ export const component: ComponentMetadata = {
|
||||
})
|
||||
},
|
||||
urlExclude: darkExcludes,
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.general,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.general],
|
||||
description: {
|
||||
'zh-CN': `
|
||||
使夜间模式同步系统设置的亮 / 暗主题, 请勿和 \`夜间模式计划时段\` 一同使用.
|
||||
|
||||
@ -8,7 +8,10 @@ const add = async () => {
|
||||
localStorage.setItem('pbp_theme_v4', 'b')
|
||||
const meta = dq('meta[name="theme-color"]') as HTMLMetaElement
|
||||
if (!meta) {
|
||||
document.head.insertAdjacentHTML('beforeend', `<meta name="theme-color" content="${darkMetaColor}">`)
|
||||
document.head.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`<meta name="theme-color" content="${darkMetaColor}">`,
|
||||
)
|
||||
} else {
|
||||
meta.dataset.light = meta.content
|
||||
meta.content = darkMetaColor
|
||||
@ -40,10 +43,7 @@ export const component = defineComponentMetadata({
|
||||
setTimeout(remove, changeDelay)
|
||||
},
|
||||
description: '启用夜间模式能更好地适应光线暗的环境, 并会大量应用主题颜色.',
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.general,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.general],
|
||||
instantStyles: [
|
||||
{
|
||||
name: 'dark-mode',
|
||||
|
||||
@ -13,14 +13,14 @@ class ScheduleTime {
|
||||
this.hour = now.getHours()
|
||||
this.minute = now.getMinutes()
|
||||
} else if (args.length === 1) {
|
||||
const [text] = args;
|
||||
[this.hour, this.minute] = text
|
||||
const [text] = args
|
||||
;[this.hour, this.minute] = text
|
||||
.split(':')
|
||||
.slice(0, 2)
|
||||
.map(it => ScheduleTime.validatePart(it))
|
||||
this.normalize()
|
||||
} else if (args.length === 2) {
|
||||
[this.hour, this.minute] = args
|
||||
;[this.hour, this.minute] = args
|
||||
}
|
||||
}
|
||||
normalize() {
|
||||
@ -40,17 +40,13 @@ class ScheduleTime {
|
||||
}
|
||||
}
|
||||
lessThan(other: ScheduleTime) {
|
||||
if (this.hour < other.hour
|
||||
|| (this.hour === other.hour && this.minute < other.minute)
|
||||
) {
|
||||
if (this.hour < other.hour || (this.hour === other.hour && this.minute < other.minute)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
greaterThan(other: ScheduleTime) {
|
||||
if (this.hour > other.hour
|
||||
|| (this.hour === other.hour && this.minute > other.minute)
|
||||
) {
|
||||
if (this.hour > other.hour || (this.hour === other.hour && this.minute > other.minute)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -113,11 +109,9 @@ const checkTime = (settings: ComponentSettings) => {
|
||||
export const component: ComponentMetadata = {
|
||||
name: 'darkModeSchedule',
|
||||
displayName: '夜间模式计划时段',
|
||||
description: '设置一个使用夜间模式的时间段, 进入 / 离开此时间段时, 会自动开启 / 关闭夜间模式. 结束时间小于起始时间时将视为次日, 如 `18:00` 至 `6:00` 表示晚上 18:00 到次日 6:00. 请勿和 \`夜间模式跟随系统\` 一同使用.',
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.general,
|
||||
],
|
||||
description:
|
||||
'设置一个使用夜间模式的时间段, 进入 / 离开此时间段时, 会自动开启 / 关闭夜间模式. 结束时间小于起始时间时将视为次日, 如 `18:00` 至 `6:00` 表示晚上 18:00 到次日 6:00. 请勿和 `夜间模式跟随系统` 一同使用.',
|
||||
tags: [componentsTags.style, componentsTags.general],
|
||||
entry: ({ settings }) => fullyLoaded(() => checkTime(settings)),
|
||||
urlExclude: darkExcludes,
|
||||
options: {
|
||||
|
||||
@ -4,9 +4,7 @@ import { bangumiUrls } from '@/core/utils/urls'
|
||||
|
||||
export const component = defineComponentMetadata({
|
||||
displayName: '隐藏番剧点评',
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.style],
|
||||
...toggleStyle('hideBangumiReviews', () => import('./reviews.scss')),
|
||||
urlInclude: bangumiUrls,
|
||||
description: {
|
||||
|
||||
@ -4,9 +4,7 @@ import { bangumiUrls } from '@/core/utils/urls'
|
||||
|
||||
export const component = defineComponentMetadata({
|
||||
displayName: '隐藏番剧承包',
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.style],
|
||||
...toggleStyle('hideBangumiSponsors', () => import('./sponsors.scss')),
|
||||
urlInclude: bangumiUrls,
|
||||
description: {
|
||||
|
||||
@ -11,10 +11,7 @@ export const component = defineComponentMetadata({
|
||||
},
|
||||
],
|
||||
displayName: '隐藏直播推荐',
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.video,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.video],
|
||||
description: {
|
||||
'zh-CN': '隐藏视频页面右侧下方的直播推荐.',
|
||||
},
|
||||
|
||||
@ -11,12 +11,10 @@ export const component = defineComponentMetadata({
|
||||
style: () => import('./related-videos.scss'),
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.video,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.video],
|
||||
description: {
|
||||
'zh-CN': '隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播 (自动播放下一个推荐视频) 功能, 需要先取消隐藏视频推荐才能看到开关.',
|
||||
'zh-CN':
|
||||
'隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播 (自动播放下一个推荐视频) 功能, 需要先取消隐藏视频推荐才能看到开关.',
|
||||
},
|
||||
urlInclude: videoAndBangumiUrls,
|
||||
})
|
||||
|
||||
@ -12,9 +12,7 @@ export const component = defineComponentMetadata({
|
||||
style: () => import('./top-mask.scss'),
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.style],
|
||||
description: {
|
||||
'zh-CN': '隐藏视频里鼠标经过时出现在右上角的覆盖层.',
|
||||
},
|
||||
|
||||
@ -4,12 +4,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default Vue.extend({
|
||||
|
||||
})
|
||||
export default Vue.extend({})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
|
||||
@ -2,11 +2,7 @@
|
||||
<HomeRedesignBase>
|
||||
<div class="fresh-home">
|
||||
<div class="fresh-home-content-layout">
|
||||
<FreshLayoutItem
|
||||
v-for="layout of layouts"
|
||||
:key="layout.name"
|
||||
:item="layout"
|
||||
/>
|
||||
<FreshLayoutItem v-for="layout of layouts" :key="layout.name" :item="layout" />
|
||||
</div>
|
||||
</div>
|
||||
</HomeRedesignBase>
|
||||
@ -29,8 +25,8 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "tabs";
|
||||
@import 'common';
|
||||
@import 'tabs';
|
||||
|
||||
.fresh-home {
|
||||
padding: 16px 36px;
|
||||
@ -65,7 +61,7 @@ export default Vue.extend({
|
||||
@include h-center(8px);
|
||||
.be-button {
|
||||
.be-icon {
|
||||
transition: .3s ease-out;
|
||||
transition: 0.3s ease-out;
|
||||
}
|
||||
.be-iconfont-left-arrow {
|
||||
transform: translateX(-0.5px);
|
||||
@ -75,7 +71,7 @@ export default Vue.extend({
|
||||
}
|
||||
.mdi-refresh {
|
||||
margin: 1px;
|
||||
transition-duration: .5s;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
&:hover .mdi-refresh {
|
||||
transform: rotate(1turn);
|
||||
@ -91,7 +87,7 @@ export default Vue.extend({
|
||||
}
|
||||
.be-icon {
|
||||
font-weight: normal;
|
||||
transition: .3s ease-out;
|
||||
transition: 0.3s ease-out;
|
||||
margin-right: 6px;
|
||||
}
|
||||
&.rotate:hover .be-icon {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-sub-header {
|
||||
@include h-center(6px);
|
||||
|
||||
@ -24,12 +24,11 @@ export default Vue.extend({
|
||||
.video-card {
|
||||
border-radius: var(--home-card-radius) !important;
|
||||
.cover-container {
|
||||
border-radius:
|
||||
calc(var(--home-card-radius) - 1px) calc(var(--home-card-radius) - 1px) 0 0 !important;
|
||||
border-radius: calc(var(--home-card-radius) - 1px) calc(var(--home-card-radius) - 1px) 0 0 !important;
|
||||
}
|
||||
&,
|
||||
& * {
|
||||
transition: .2s ease-out;
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,13 +8,7 @@
|
||||
<VLoading v-if="loading" />
|
||||
<VEmpty v-else />
|
||||
</div>
|
||||
<VideoCardWrapper
|
||||
v-for="video of videos"
|
||||
v-else
|
||||
ref="cards"
|
||||
:key="video.id"
|
||||
:data="video"
|
||||
/>
|
||||
<VideoCardWrapper v-for="video of videos" v-else ref="cards" :key="video.id" :data="video" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -57,13 +51,17 @@ export default Vue.extend({
|
||||
mounted() {
|
||||
const container = this.$refs.content as HTMLElement
|
||||
let cancel: () => void
|
||||
addComponentListener('freshHome.horizontalWheelScroll', (scroll: boolean) => {
|
||||
if (scroll) {
|
||||
cancel = enableHorizontalScroll(container)
|
||||
} else {
|
||||
cancel?.()
|
||||
}
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'freshHome.horizontalWheelScroll',
|
||||
(scroll: boolean) => {
|
||||
if (scroll) {
|
||||
cancel = enableHorizontalScroll(container)
|
||||
} else {
|
||||
cancel?.()
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
async setupIntersection() {
|
||||
@ -77,7 +75,9 @@ export default Vue.extend({
|
||||
const container = this.$refs.content as HTMLElement
|
||||
const style = getComputedStyle(container)
|
||||
const containerWidth = container.clientWidth
|
||||
const wrapperWidth = parseFloat(style.getPropertyValue('--card-width')) + parseFloat(style.getPropertyValue('--card-padding'))
|
||||
const wrapperWidth =
|
||||
parseFloat(style.getPropertyValue('--card-width')) +
|
||||
parseFloat(style.getPropertyValue('--card-padding'))
|
||||
const pageWidth = Math.trunc(containerWidth / wrapperWidth) * wrapperWidth
|
||||
container.scrollBy(offset * pageWidth, 0)
|
||||
},
|
||||
@ -85,8 +85,8 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "effects";
|
||||
@import 'common';
|
||||
@import 'effects';
|
||||
|
||||
.fresh-home-video-list {
|
||||
--card-height: var(--home-content-height);
|
||||
|
||||
@ -8,13 +8,15 @@ export const component = defineComponentMetadata({
|
||||
name: 'freshHome',
|
||||
displayName: '清爽首页',
|
||||
urlInclude: homeUrls,
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.style],
|
||||
entry: () => {
|
||||
addComponentListener('freshHome.maxWidth', (width: number) => {
|
||||
document.documentElement.style.setProperty('--home-max-width-override', `${width}px`)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'freshHome.maxWidth',
|
||||
(width: number) => {
|
||||
document.documentElement.style.setProperty('--home-max-width-override', `${width}px`)
|
||||
},
|
||||
true,
|
||||
)
|
||||
contentLoaded(async () => {
|
||||
const FreshHome = await import('./FreshHome.vue')
|
||||
const freshHome = mountVueComponent(FreshHome)
|
||||
|
||||
@ -1,25 +1,17 @@
|
||||
<template>
|
||||
<div class="fresh-home-areas">
|
||||
<div class="fresh-home-header">
|
||||
<div class="fresh-home-header-title">
|
||||
栏目
|
||||
</div>
|
||||
<div class="fresh-home-header-title">栏目</div>
|
||||
</div>
|
||||
<div class="fresh-home-areas-content">
|
||||
<a class="fresh-home-areas-content-primary" :href="primary.url" target="_blank">
|
||||
<div class="fresh-home-areas-content-primary-image">
|
||||
</div>
|
||||
<div class="fresh-home-areas-content-primary-image"></div>
|
||||
<div class="fresh-home-areas-content-primary-title">
|
||||
{{ primary.title }}
|
||||
</div>
|
||||
</a>
|
||||
<div class="fresh-home-areas-content-other">
|
||||
<a
|
||||
v-for="other of others"
|
||||
:key="other.title"
|
||||
:href="other.url"
|
||||
target="_blank"
|
||||
>
|
||||
<a v-for="other of others" :key="other.title" :href="other.url" target="_blank">
|
||||
<VButton type="transparent">
|
||||
<VIcon colored :icon="other.icon" :size="22" />
|
||||
{{ other.title }}
|
||||
@ -76,7 +68,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-areas {
|
||||
@include v-stretch();
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div class="fresh-home-blackboard" @mouseenter="destroyTimer" @mouseleave="createTimer">
|
||||
<div class="fresh-home-header">
|
||||
<div class="fresh-home-header-title">
|
||||
活动
|
||||
</div>
|
||||
<a class="fresh-home-header-icon-button rotate" href="https://www.bilibili.com/blackboard/x/act_list/" target="_blank">
|
||||
<div class="fresh-home-header-title">活动</div>
|
||||
<a
|
||||
class="fresh-home-header-icon-button rotate"
|
||||
href="https://www.bilibili.com/blackboard/x/act_list/"
|
||||
target="_blank"
|
||||
>
|
||||
<VButton round>
|
||||
<VIcon icon="mdi-dots-horizontal" :size="20"></VIcon>
|
||||
更多
|
||||
@ -43,22 +45,14 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="fresh-home-blackboard-jump-dots">
|
||||
<label
|
||||
v-for="(b, i) of blackboards"
|
||||
:key="i"
|
||||
:for="'blackboard' + i"
|
||||
>
|
||||
<label v-for="(b, i) of blackboards" :key="i" :for="'blackboard' + i">
|
||||
<div class="fresh-home-blackboard-jump-dot"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
VButton,
|
||||
VIcon,
|
||||
DpiImage,
|
||||
} from '@/ui'
|
||||
import { VButton, VIcon, DpiImage } from '@/ui'
|
||||
import { getBlackboards } from './api'
|
||||
|
||||
export default Vue.extend({
|
||||
@ -98,18 +92,14 @@ export default Vue.extend({
|
||||
if (!document.hasFocus() || this.$el.matches(':hover')) {
|
||||
return
|
||||
}
|
||||
const currentIndex = parseInt(
|
||||
dq(`.${radioClass}:checked`).getAttribute('data-index'),
|
||||
)
|
||||
const currentIndex = parseInt(dq(`.${radioClass}:checked`).getAttribute('data-index'))
|
||||
let targetIndex: number
|
||||
if (currentIndex === this.blackboards.length - 1) {
|
||||
targetIndex = 0
|
||||
} else {
|
||||
targetIndex = currentIndex + 1
|
||||
}
|
||||
(dq(
|
||||
`.${radioClass}[data-index='${targetIndex}']`,
|
||||
) as HTMLInputElement).checked = true
|
||||
;(dq(`.${radioClass}[data-index='${targetIndex}']`) as HTMLInputElement).checked = true
|
||||
}, 5000)
|
||||
},
|
||||
destroyTimer() {
|
||||
@ -123,7 +113,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
$max-card-count: 16;
|
||||
.fresh-home {
|
||||
@ -131,7 +121,7 @@ $max-card-count: 16;
|
||||
position: relative;
|
||||
&,
|
||||
& * {
|
||||
transition: .2s ease-out;
|
||||
transition: 0.2s ease-out;
|
||||
}
|
||||
&-cards {
|
||||
display: flex;
|
||||
@ -194,8 +184,8 @@ $max-card-count: 16;
|
||||
width: 40px;
|
||||
}
|
||||
&:checked:nth-of-type(#{$i}) ~ .fresh-home-blackboard-cards .fresh-home-blackboard-card {
|
||||
transform:
|
||||
translateX(calc(-1 * #{$i - 1} * var(--blackboard-width-without-border))) scale(0.9);
|
||||
transform: translateX(calc(-1 * #{$i - 1} * var(--blackboard-width-without-border)))
|
||||
scale(0.9);
|
||||
&:nth-of-type(#{$i}) {
|
||||
transform: translateX(calc(-1 * #{$i - 1} * var(--blackboard-width-without-border)));
|
||||
img {
|
||||
|
||||
@ -14,11 +14,14 @@ export const getBlackboards = async (): Promise<Blackboard[]> => {
|
||||
throw new Error(`获取活动卡片失败: ${message}`)
|
||||
}
|
||||
const list: any[] = data[locId]
|
||||
return list.map(it => ({
|
||||
url: it.url,
|
||||
title: it.name,
|
||||
// isAd: it.is_ad_loc,
|
||||
isAd: it.res_id !== locId,
|
||||
imageUrl: it.pic,
|
||||
} as Blackboard))
|
||||
return list.map(
|
||||
it =>
|
||||
({
|
||||
url: it.url,
|
||||
title: it.name,
|
||||
// isAd: it.is_ad_loc,
|
||||
isAd: it.res_id !== locId,
|
||||
imageUrl: it.pic,
|
||||
} as Blackboard),
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="fresh-home-categories">
|
||||
<div class="fresh-home-header">
|
||||
<div class="fresh-home-header-title">
|
||||
分区
|
||||
</div>
|
||||
<div class="fresh-home-header-title">分区</div>
|
||||
<div class="fresh-home-header-center-area">
|
||||
<div class="fresh-home-header-tabs">
|
||||
<div ref="tabs" class="default-tabs">
|
||||
@ -105,7 +103,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-categories {
|
||||
@include v-stretch();
|
||||
|
||||
@ -2,13 +2,9 @@
|
||||
<div class="fresh-home-categories-bangumi">
|
||||
<div class="fresh-home-categories-bangumi-timeline">
|
||||
<div class="fresh-home-categories-bangumi-timeline-header">
|
||||
<SubHeader>
|
||||
时间表
|
||||
</SubHeader>
|
||||
<SubHeader> 时间表 </SubHeader>
|
||||
</div>
|
||||
<BangumiTimeline
|
||||
:api="timelineApi"
|
||||
/>
|
||||
<BangumiTimeline :api="timelineApi" />
|
||||
</div>
|
||||
<div class="fresh-home-categories-bangumi-rank-list">
|
||||
<a
|
||||
@ -16,15 +12,9 @@
|
||||
:href="rankingsLink"
|
||||
target="_blank"
|
||||
>
|
||||
<SubHeader>
|
||||
排行榜
|
||||
</SubHeader>
|
||||
<SubHeader> 排行榜 </SubHeader>
|
||||
</a>
|
||||
<RankList
|
||||
bangumi-mode
|
||||
:parse-json="parseJson"
|
||||
:api="rankingsApi"
|
||||
/>
|
||||
<RankList bangumi-mode :parse-json="parseJson" :api="rankingsApi" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -73,22 +63,20 @@ export default Vue.extend({
|
||||
parseJson(json: any) {
|
||||
const items = (json.data?.list ?? []) as any[]
|
||||
const cards = items
|
||||
.map(
|
||||
(item): RankListCard => {
|
||||
const upName = item.new_ep?.index_show ?? item.title
|
||||
return {
|
||||
id: item.season_id,
|
||||
title: item.title,
|
||||
playCount: item.stat.view,
|
||||
points: item.stat.follow,
|
||||
upHref: item.url,
|
||||
upName,
|
||||
dynamic: upName,
|
||||
coverUrl: item.new_ep?.cover ?? item.ss_horizontal_cover,
|
||||
videoHref: item.url,
|
||||
}
|
||||
},
|
||||
)
|
||||
.map((item): RankListCard => {
|
||||
const upName = item.new_ep?.index_show ?? item.title
|
||||
return {
|
||||
id: item.season_id,
|
||||
title: item.title,
|
||||
playCount: item.stat.view,
|
||||
points: item.stat.follow,
|
||||
upHref: item.url,
|
||||
upName,
|
||||
dynamic: upName,
|
||||
coverUrl: item.new_ep?.cover ?? item.ss_horizontal_cover,
|
||||
videoHref: item.url,
|
||||
}
|
||||
})
|
||||
.slice(0, 10)
|
||||
return applyContentFilter(cards)
|
||||
},
|
||||
@ -96,8 +84,8 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "effects";
|
||||
@import 'common';
|
||||
@import 'effects';
|
||||
|
||||
.fresh-home-categories-bangumi {
|
||||
@include h-stretch(var(--fresh-home-categories-column-gap));
|
||||
|
||||
@ -25,19 +25,13 @@
|
||||
<div class="fresh-home-categories-bangumi-timeline-date-text">
|
||||
{{ dayOfWeekText(item) }}
|
||||
</div>
|
||||
<div
|
||||
v-if="index === todayIndex"
|
||||
class="fresh-home-categories-bangumi-timeline-date-today"
|
||||
>
|
||||
<div v-if="index === todayIndex" class="fresh-home-categories-bangumi-timeline-date-today">
|
||||
TODAY
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref="seasonsList"
|
||||
class="
|
||||
fresh-home-categories-bangumi-timeline-seasons-container
|
||||
scroll-top scroll-bottom
|
||||
"
|
||||
class="fresh-home-categories-bangumi-timeline-seasons-container scroll-top scroll-bottom"
|
||||
:class="{ 'not-empty': item.episodes.length > 0 }"
|
||||
>
|
||||
<div
|
||||
@ -88,19 +82,13 @@
|
||||
follow: season.follow,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="fresh-home-categories-bangumi-timeline-season-time-icon"
|
||||
>
|
||||
<div class="fresh-home-categories-bangumi-timeline-season-time-icon">
|
||||
<VIcon
|
||||
:icon="
|
||||
season.follow ? 'mdi-heart-outline' : 'mdi-progress-clock'
|
||||
"
|
||||
:icon="season.follow ? 'mdi-heart-outline' : 'mdi-progress-clock'"
|
||||
:size="14"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="fresh-home-categories-bangumi-timeline-season-time-text"
|
||||
>
|
||||
<div class="fresh-home-categories-bangumi-timeline-season-time-text">
|
||||
{{ season.pub_time }}
|
||||
</div>
|
||||
</div>
|
||||
@ -111,12 +99,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
DpiImage,
|
||||
VIcon,
|
||||
VEmpty,
|
||||
VLoading,
|
||||
} from '@/ui'
|
||||
import { DpiImage, VIcon, VEmpty, VLoading } from '@/ui'
|
||||
import { addComponentListener } from '@/core/settings'
|
||||
import { enableHorizontalScroll } from '@/core/horizontal-scroll'
|
||||
import { cssVariableMixin, requestMixin } from '../../../../mixin'
|
||||
@ -157,15 +140,9 @@ const timelineCssVars = (() => {
|
||||
const seasonTodayWidth = 250
|
||||
const timelineItemHeight = 66
|
||||
const timelineTodayHeight = 96
|
||||
const timelineViewportItemsHeight = (
|
||||
6 * timelineItemHeight + timelineTodayHeight
|
||||
)
|
||||
const timelineItemGap = (
|
||||
rankListHeight - timelineViewportItemsHeight
|
||||
) / 6
|
||||
const timelineViewportHeight = (
|
||||
6 * timelineItemGap + timelineViewportItemsHeight
|
||||
)
|
||||
const timelineViewportItemsHeight = 6 * timelineItemHeight + timelineTodayHeight
|
||||
const timelineItemGap = (rankListHeight - timelineViewportItemsHeight) / 6
|
||||
const timelineViewportHeight = 6 * timelineItemGap + timelineViewportItemsHeight
|
||||
return {
|
||||
seasonItemWidth,
|
||||
seasonTodayWidth,
|
||||
@ -243,21 +220,22 @@ export default Vue.extend({
|
||||
await this.$nextTick()
|
||||
const list: HTMLElement[] = this.$refs.seasonsList
|
||||
let cancelAll: () => void
|
||||
addComponentListener('freshHome.horizontalWheelScroll', (scroll: boolean) => {
|
||||
if (scroll) {
|
||||
const cancel = list
|
||||
.flatMap(it => [...it.children])
|
||||
.map(it => enableHorizontalScroll(it as HTMLElement))
|
||||
cancelAll = () => cancel.forEach(fn => fn())
|
||||
} else {
|
||||
cancelAll?.()
|
||||
}
|
||||
}, true)
|
||||
const root: HTMLElement = this.$el
|
||||
root.scrollTop = (
|
||||
5 * timelineCssVars.timelineItemHeight
|
||||
+ 5 * timelineCssVars.timelineItemGap
|
||||
addComponentListener(
|
||||
'freshHome.horizontalWheelScroll',
|
||||
(scroll: boolean) => {
|
||||
if (scroll) {
|
||||
const cancel = list
|
||||
.flatMap(it => [...it.children])
|
||||
.map(it => enableHorizontalScroll(it as HTMLElement))
|
||||
cancelAll = () => cancel.forEach(fn => fn())
|
||||
} else {
|
||||
cancelAll?.()
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
const root: HTMLElement = this.$el
|
||||
root.scrollTop = 5 * timelineCssVars.timelineItemHeight + 5 * timelineCssVars.timelineItemGap
|
||||
|
||||
const classPrefix = '.fresh-home-categories-bangumi-timeline'
|
||||
list.forEach(seasons => {
|
||||
@ -279,7 +257,10 @@ export default Vue.extend({
|
||||
this.scrolled = true
|
||||
return
|
||||
}
|
||||
const lastPublishedElement = dq(todaySeasons, `[data-season="${lastPublishedItem.season_id}"]`) as HTMLElement
|
||||
const lastPublishedElement = dq(
|
||||
todaySeasons,
|
||||
`[data-season="${lastPublishedItem.season_id}"]`,
|
||||
) as HTMLElement
|
||||
if (!lastPublishedElement) {
|
||||
return
|
||||
}
|
||||
@ -299,23 +280,14 @@ export default Vue.extend({
|
||||
return season.pub_ts * 1000 <= this.now
|
||||
},
|
||||
dayOfWeekText(item: TimelineDay) {
|
||||
return `周${[
|
||||
'日',
|
||||
'一',
|
||||
'二',
|
||||
'三',
|
||||
'四',
|
||||
'五',
|
||||
'六',
|
||||
'日',
|
||||
][item.day_of_week]}`
|
||||
return `周${['日', '一', '二', '三', '四', '五', '六', '日'][item.day_of_week]}`
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "effects";
|
||||
@import 'common';
|
||||
@import 'effects';
|
||||
|
||||
.fresh-home-categories-bangumi {
|
||||
&-timeline {
|
||||
@ -377,16 +349,13 @@ export default Vue.extend({
|
||||
$icon-height: 48;
|
||||
--scale-factor-x: calc(#{$icon-width} / 38);
|
||||
--scale-factor-y: calc(#{$icon-height} / 36);
|
||||
background-size: calc(247px * var(--scale-factor-x))
|
||||
calc(663px * var(--scale-factor-y));
|
||||
background-size: calc(247px * var(--scale-factor-x)) calc(663px * var(--scale-factor-y));
|
||||
width: #{$icon-width}px;
|
||||
height: #{$icon-height}px;
|
||||
background-position-x: calc(-146px * var(--scale-factor-x));
|
||||
@for $day from 1 through 7 {
|
||||
&.day-of-week-#{$day} {
|
||||
background-position-y: calc(
|
||||
#{-36 - 72 * ($day - 1)}px * var(--scale-factor-y)
|
||||
);
|
||||
background-position-y: calc(#{-36 - 72 * ($day - 1)}px * var(--scale-factor-y));
|
||||
}
|
||||
}
|
||||
body.dark & {
|
||||
@ -485,8 +454,7 @@ export default Vue.extend({
|
||||
&.today {
|
||||
border-radius: 12px;
|
||||
&.follow.published {
|
||||
box-shadow: 0 0 0 2px var(--theme-color),
|
||||
0 0 0 5px var(--theme-color-20);
|
||||
box-shadow: 0 0 0 2px var(--theme-color), 0 0 0 5px var(--theme-color-20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,28 +2,19 @@
|
||||
<div class="fresh-home-categories-default">
|
||||
<div class="fresh-home-categories-default-video-column">
|
||||
<div class="fresh-home-categories-default-video-column-item">
|
||||
<SubHeader>
|
||||
有新动态
|
||||
</SubHeader>
|
||||
<SubHeader> 有新动态 </SubHeader>
|
||||
<VideoSlides :api="activeVideosApi" />
|
||||
</div>
|
||||
<div class="fresh-home-categories-default-video-column-item">
|
||||
<SubHeader>
|
||||
最新发布
|
||||
</SubHeader>
|
||||
<SubHeader> 最新发布 </SubHeader>
|
||||
<VideoSlides :api="newVideosApi" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="fresh-home-categories-default-rank-list">
|
||||
<a :href="rankingsLink" target="_blank">
|
||||
<SubHeader>
|
||||
排行榜
|
||||
</SubHeader>
|
||||
<SubHeader> 排行榜 </SubHeader>
|
||||
</a>
|
||||
<RankList
|
||||
:parse-json="parseJson"
|
||||
:api="rankingsApi"
|
||||
/>
|
||||
<RankList :parse-json="parseJson" :api="rankingsApi" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -87,7 +78,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-categories-default {
|
||||
@include h-stretch(var(--fresh-home-categories-column-gap));
|
||||
|
||||
@ -4,11 +4,7 @@
|
||||
<VLoading v-if="loading" />
|
||||
<div v-if="(error || items.length === 0) && !loading" class="fresh-home-rank-list-empty">
|
||||
<VEmpty />
|
||||
<VButton
|
||||
class="fresh-home-rank-list-refresh-button"
|
||||
round
|
||||
@click="reload"
|
||||
>
|
||||
<VButton class="fresh-home-rank-list-refresh-button" round @click="reload">
|
||||
<VIcon icon="mdi-refresh" />
|
||||
刷新
|
||||
</VButton>
|
||||
@ -25,11 +21,7 @@
|
||||
>
|
||||
{{ firstItem.title }}
|
||||
</a>
|
||||
<a
|
||||
class="fresh-home-rank-list-cover"
|
||||
target="_blank"
|
||||
:href="firstItem.videoHref"
|
||||
>
|
||||
<a class="fresh-home-rank-list-cover" target="_blank" :href="firstItem.videoHref">
|
||||
<DpiImage
|
||||
:src="firstItem.coverUrl"
|
||||
:size="{ width: ui.firstCoverWidth, height: ui.firstCoverHeight }"
|
||||
@ -51,15 +43,8 @@
|
||||
<div class="fresh-home-rank-list-laser" data-number="1"></div>
|
||||
</div>
|
||||
<div v-if="secondItem" class="fresh-home-rank-list-second-item animation">
|
||||
<a
|
||||
class="fresh-home-rank-list-rank-item"
|
||||
target="_blank"
|
||||
:href="secondItem.videoHref"
|
||||
>
|
||||
<div
|
||||
class="fresh-home-rank-list-rank-item-title"
|
||||
:title="secondItem.title"
|
||||
>
|
||||
<a class="fresh-home-rank-list-rank-item" target="_blank" :href="secondItem.videoHref">
|
||||
<div class="fresh-home-rank-list-rank-item-title" :title="secondItem.title">
|
||||
{{ secondItem.title }}
|
||||
</div>
|
||||
<UpInfo
|
||||
@ -78,11 +63,7 @@
|
||||
{{ secondItem.playCount | formatCount }}
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="fresh-home-rank-list-cover"
|
||||
target="_blank"
|
||||
:href="secondItem.videoHref"
|
||||
>
|
||||
<a class="fresh-home-rank-list-cover" target="_blank" :href="secondItem.videoHref">
|
||||
<DpiImage
|
||||
:src="secondItem.coverUrl"
|
||||
:size="{ width: ui.secondCoverWidth, height: ui.secondCoverHeight }"
|
||||
@ -91,15 +72,8 @@
|
||||
<div class="fresh-home-rank-list-laser" data-number="2"></div>
|
||||
</div>
|
||||
<div v-if="thirdItem" class="fresh-home-rank-list-third-item animation">
|
||||
<a
|
||||
class="fresh-home-rank-list-rank-item"
|
||||
target="_blank"
|
||||
:href="thirdItem.videoHref"
|
||||
>
|
||||
<div
|
||||
class="fresh-home-rank-list-rank-item-title"
|
||||
:title="thirdItem.title"
|
||||
>
|
||||
<a class="fresh-home-rank-list-rank-item" target="_blank" :href="thirdItem.videoHref">
|
||||
<div class="fresh-home-rank-list-rank-item-title" :title="thirdItem.title">
|
||||
{{ thirdItem.title }}
|
||||
</div>
|
||||
<UpInfo
|
||||
@ -118,11 +92,7 @@
|
||||
{{ secondItem.playCount | formatCount }}
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="fresh-home-rank-list-cover"
|
||||
target="_blank"
|
||||
:href="thirdItem.videoHref"
|
||||
>
|
||||
<a class="fresh-home-rank-list-cover" target="_blank" :href="thirdItem.videoHref">
|
||||
<DpiImage
|
||||
:src="thirdItem.coverUrl"
|
||||
:size="{ width: ui.thirdCoverWidth, height: ui.thirdCoverHeight }"
|
||||
@ -136,13 +106,7 @@
|
||||
<script lang="ts">
|
||||
import UpInfo from '@/components/feeds/UpInfo.vue'
|
||||
import { formatCount } from '@/core/utils/formatters'
|
||||
import {
|
||||
DpiImage,
|
||||
VIcon,
|
||||
VLoading,
|
||||
VEmpty,
|
||||
VButton,
|
||||
} from '@/ui'
|
||||
import { DpiImage, VIcon, VLoading, VEmpty, VButton } from '@/ui'
|
||||
import { requestMixin, cssVariableMixin } from '../../../../mixin'
|
||||
import { rankListCssVars } from './rank-list'
|
||||
|
||||
@ -158,10 +122,7 @@ export default Vue.extend({
|
||||
filters: {
|
||||
formatCount,
|
||||
},
|
||||
mixins: [
|
||||
requestMixin(),
|
||||
cssVariableMixin(rankListCssVars),
|
||||
],
|
||||
mixins: [requestMixin(), cssVariableMixin(rankListCssVars)],
|
||||
props: {
|
||||
parseJson: {
|
||||
type: Function,
|
||||
@ -201,7 +162,7 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-rank-list {
|
||||
position: relative;
|
||||
@ -225,7 +186,7 @@ export default Vue.extend({
|
||||
& &-stats {
|
||||
@include h-center(12px);
|
||||
font-size: 12px;
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
margin: 0 10px;
|
||||
.be-icon {
|
||||
margin-right: -8px;
|
||||
@ -243,7 +204,7 @@ export default Vue.extend({
|
||||
|
||||
&-title {
|
||||
@include semi-bold();
|
||||
transition: color .2s ease-out;
|
||||
transition: color 0.2s ease-out;
|
||||
line-height: var(--rank-item-title-height);
|
||||
box-sizing: content-box;
|
||||
&:hover {
|
||||
@ -266,7 +227,7 @@ export default Vue.extend({
|
||||
}
|
||||
}
|
||||
@include v-stretch();
|
||||
animation: .4s var(--animation-timing) first-animation paused both;
|
||||
animation: 0.4s var(--animation-timing) first-animation paused both;
|
||||
position: absolute;
|
||||
top: var(--padding);
|
||||
left: var(--padding);
|
||||
@ -317,7 +278,7 @@ export default Vue.extend({
|
||||
}
|
||||
}
|
||||
@include v-stretch();
|
||||
animation: .4s var(--animation-timing) second-animation paused both;
|
||||
animation: 0.4s var(--animation-timing) second-animation paused both;
|
||||
position: absolute;
|
||||
top: var(--offset-second);
|
||||
bottom: var(--padding);
|
||||
@ -350,7 +311,7 @@ export default Vue.extend({
|
||||
}
|
||||
}
|
||||
@include v-stretch();
|
||||
animation: .4s var(--animation-timing) third-animation paused both;
|
||||
animation: 0.4s var(--animation-timing) third-animation paused both;
|
||||
position: absolute;
|
||||
top: var(--offset-third);
|
||||
right: var(--padding);
|
||||
@ -379,7 +340,7 @@ export default Vue.extend({
|
||||
box-shadow: none;
|
||||
overflow: hidden;
|
||||
transform-origin: bottom;
|
||||
transition: .2s ease-out;
|
||||
transition: 0.2s ease-out;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
@ -398,11 +359,7 @@ export default Vue.extend({
|
||||
flex: 1;
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
var(--theme-color) 0%,
|
||||
var(--theme-color-10) 100%
|
||||
);
|
||||
background-image: linear-gradient(to bottom, var(--theme-color) 0%, var(--theme-color-10) 100%);
|
||||
&::after {
|
||||
content: attr(data-number);
|
||||
@include absolute-center();
|
||||
@ -436,7 +393,7 @@ export default Vue.extend({
|
||||
}
|
||||
.be-icon {
|
||||
margin-right: 6px;
|
||||
transition: .5s ease-out;
|
||||
transition: 0.5s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,19 +18,12 @@
|
||||
</div>
|
||||
<div class="cover-placeholder-vertical"></div>
|
||||
<div v-if="!loaded" class="fresh-home-video-slides-empty">
|
||||
<div
|
||||
class="empty-placeholder fresh-home-video-slides-main-title"
|
||||
v-text="' '"
|
||||
></div>
|
||||
<div class="empty-placeholder fresh-home-video-slides-main-title" v-text="' '"></div>
|
||||
<div class="empty-indicator">
|
||||
<VLoading v-if="loading" />
|
||||
<div v-if="error" class="empty-indicator-error">
|
||||
<VEmpty />
|
||||
<VButton
|
||||
class="fresh-home-video-slides-refresh-button"
|
||||
round
|
||||
@click="reload"
|
||||
>
|
||||
<VButton class="fresh-home-video-slides-refresh-button" round @click="reload">
|
||||
<VIcon icon="mdi-refresh" />
|
||||
刷新
|
||||
</VButton>
|
||||
@ -42,11 +35,7 @@
|
||||
<div class="fresh-home-video-slides-row">
|
||||
<div class="cover-placeholder-horizontal"></div>
|
||||
<div class="fresh-home-video-slides-main-actions">
|
||||
<a
|
||||
class="fresh-home-video-slides-play-button"
|
||||
:href="currentUrl"
|
||||
target="_blank"
|
||||
>
|
||||
<a class="fresh-home-video-slides-play-button" :href="currentUrl" target="_blank">
|
||||
<VButton type="primary" round>
|
||||
<VIcon icon="mdi-play" />
|
||||
播放
|
||||
@ -96,12 +85,7 @@
|
||||
<div class="description-text" v-text="currentItem.description"></div>
|
||||
</div>
|
||||
<div class="fresh-home-video-slides-actions">
|
||||
<VButton
|
||||
class="fresh-home-video-slides-refresh-button"
|
||||
title="刷新"
|
||||
icon
|
||||
@click="reload"
|
||||
>
|
||||
<VButton class="fresh-home-video-slides-refresh-button" title="刷新" icon @click="reload">
|
||||
<VIcon icon="mdi-refresh" />
|
||||
</VButton>
|
||||
<VButton
|
||||
@ -112,12 +96,7 @@
|
||||
>
|
||||
<VIcon icon="mdi-arrow-left" />
|
||||
</VButton>
|
||||
<VButton
|
||||
class="fresh-home-video-slides-next-button"
|
||||
title="下一个"
|
||||
icon
|
||||
@click="nextCard"
|
||||
>
|
||||
<VButton class="fresh-home-video-slides-next-button" title="下一个" icon @click="nextCard">
|
||||
<VIcon icon="mdi-arrow-right" :size="36" />
|
||||
</VButton>
|
||||
</div>
|
||||
@ -140,15 +119,18 @@ export default Vue.extend({
|
||||
VLoading,
|
||||
VEmpty,
|
||||
},
|
||||
mixins: [requestMixin(), cssVariableMixin({
|
||||
mainCoverHeight: 185,
|
||||
mainCoverWidth: 287,
|
||||
otherCoverHeight: 100,
|
||||
otherCoverWidth: 154,
|
||||
mainPaddingX: 18,
|
||||
mainPaddingY: 20,
|
||||
coverPadding: 16,
|
||||
})],
|
||||
mixins: [
|
||||
requestMixin(),
|
||||
cssVariableMixin({
|
||||
mainCoverHeight: 185,
|
||||
mainCoverWidth: 287,
|
||||
otherCoverHeight: 100,
|
||||
otherCoverWidth: 154,
|
||||
mainPaddingX: 18,
|
||||
mainPaddingY: 20,
|
||||
coverPadding: 16,
|
||||
}),
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
watchlaterList,
|
||||
@ -224,8 +206,8 @@ export default Vue.extend({
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import "effects";
|
||||
@import 'common';
|
||||
@import 'effects';
|
||||
|
||||
.fresh-home-video-slides {
|
||||
@include card(12px);
|
||||
@ -339,9 +321,7 @@ export default Vue.extend({
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
padding-top: var(--main-info-padding);
|
||||
width: calc(
|
||||
var(--main-cover-width) + var(--cover-padding) + var(--other-cover-width)
|
||||
);
|
||||
width: calc(var(--main-cover-width) + var(--cover-padding) + var(--other-cover-width));
|
||||
}
|
||||
& &-main-title {
|
||||
font-size: 16px;
|
||||
@ -403,9 +383,7 @@ export default Vue.extend({
|
||||
}
|
||||
&:nth-child(1) {
|
||||
opacity: 0;
|
||||
transform: translateX(
|
||||
calc(0px - var(--other-cover-width) - var(--cover-padding))
|
||||
);
|
||||
transform: translateX(calc(0px - var(--other-cover-width) - var(--cover-padding)));
|
||||
}
|
||||
&:nth-child(2) {
|
||||
width: var(--main-cover-width);
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
const bangumiNames = [
|
||||
'番剧',
|
||||
'国创',
|
||||
]
|
||||
const bangumiNames = ['番剧', '国创']
|
||||
export const getContent = (tabName: string) => {
|
||||
console.log('getContent', tabName)
|
||||
if (bangumiNames.includes(tabName)) {
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="fresh-home-feeds">
|
||||
<div class="fresh-home-header">
|
||||
<div class="fresh-home-header-title">
|
||||
动态
|
||||
</div>
|
||||
<div class="fresh-home-header-title">动态</div>
|
||||
<div class="fresh-home-header-center-area">
|
||||
<div class="fresh-home-header-tabs">
|
||||
<div class="default-tabs">
|
||||
@ -22,11 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fresh-home-header-pagination">
|
||||
<a
|
||||
href="https://www.bilibili.com/video/online.html"
|
||||
target="_blank"
|
||||
title="在线列表"
|
||||
>
|
||||
<a href="https://www.bilibili.com/video/online.html" target="_blank" title="在线列表">
|
||||
<VButton icon>
|
||||
<VIcon icon="mdi-account-group-outline" :size="19" />
|
||||
</VButton>
|
||||
@ -53,11 +47,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fresh-home-feeds-content">
|
||||
<VideoList
|
||||
ref="videoList"
|
||||
:videos="videos"
|
||||
:loading="loading"
|
||||
/>
|
||||
<VideoList ref="videoList" :videos="videos" :loading="loading" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -113,13 +103,15 @@ export default Vue.extend({
|
||||
async reload() {
|
||||
this.loading = true
|
||||
this.videos = []
|
||||
this.videos = await this.selectedTab.api().finally(() => { this.loading = false })
|
||||
this.videos = await this.selectedTab.api().finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-feeds {
|
||||
@include v-stretch();
|
||||
|
||||
@ -5,11 +5,5 @@ import { categories } from './categories/categories'
|
||||
import { feeds } from './feeds/feeds'
|
||||
import { trending } from './trending/trending'
|
||||
|
||||
const builtInLayouts = [
|
||||
blackboard,
|
||||
trending,
|
||||
feeds,
|
||||
areas,
|
||||
categories,
|
||||
]
|
||||
const builtInLayouts = [blackboard, trending, feeds, areas, categories]
|
||||
export const [layouts] = registerAndGetData('homeRedesign.fresh.layouts', [...builtInLayouts])
|
||||
|
||||
@ -17,19 +17,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fresh-home-trending-content">
|
||||
<VideoList
|
||||
ref="videoList"
|
||||
:videos="videos"
|
||||
:loading="loading"
|
||||
/>
|
||||
<VideoList ref="videoList" :videos="videos" :loading="loading" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
VButton,
|
||||
VIcon,
|
||||
} from '@/ui'
|
||||
import { VButton, VIcon } from '@/ui'
|
||||
import VideoList from '../../VideoList.vue'
|
||||
import { freshHomeOptions } from '../../types'
|
||||
import { getTrendingVideos } from '../../../trending'
|
||||
@ -61,14 +54,15 @@ export default Vue.extend({
|
||||
async reload() {
|
||||
this.loading = true
|
||||
this.videos = []
|
||||
this.videos = await getTrendingVideos(freshHomeOptions.personalized)
|
||||
.finally(() => { this.loading = false })
|
||||
this.videos = await getTrendingVideos(freshHomeOptions.personalized).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
@import 'common';
|
||||
|
||||
.fresh-home-trending {
|
||||
@include v-stretch();
|
||||
|
||||
@ -17,10 +17,8 @@ export const setupScrollMask = (config: ScrollMaskConfig) => {
|
||||
}
|
||||
const observerConfig: IntersectionObserverInit = { threshold: [1], root: container }
|
||||
const [firstItem] = items
|
||||
const [firstObserver] = intersectionObserve(
|
||||
[firstItem],
|
||||
observerConfig,
|
||||
records => records.forEach(r => {
|
||||
const [firstObserver] = intersectionObserve([firstItem], observerConfig, records =>
|
||||
records.forEach(r => {
|
||||
const isScrollTop = r.isIntersecting && r.intersectionRatio === 1
|
||||
container.classList.toggle('scroll-top', isScrollTop)
|
||||
}),
|
||||
@ -30,10 +28,8 @@ export const setupScrollMask = (config: ScrollMaskConfig) => {
|
||||
newObservers.push(firstObserver)
|
||||
if (items.length > 1) {
|
||||
const lastItem = items[items.length - 1]
|
||||
const [lastObserver] = intersectionObserve(
|
||||
[lastItem],
|
||||
observerConfig,
|
||||
records => records.forEach(r => {
|
||||
const [lastObserver] = intersectionObserve([lastItem], observerConfig, records =>
|
||||
records.forEach(r => {
|
||||
const isScrollBottom = r.isIntersecting && r.intersectionRatio === 1
|
||||
container.classList.toggle('scroll-bottom', isScrollBottom)
|
||||
}),
|
||||
|
||||
@ -39,13 +39,17 @@ export default Vue.extend({
|
||||
},
|
||||
mounted() {
|
||||
const columnCountKey = '--minimal-home-column-count-override'
|
||||
addComponentListener('minimalHome.columnCount', (count: number) => {
|
||||
if (count > 0) {
|
||||
(this.$el as HTMLElement).style.setProperty(columnCountKey, count.toString())
|
||||
} else {
|
||||
(this.$el as HTMLElement).style.removeProperty(columnCountKey)
|
||||
}
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'minimalHome.columnCount',
|
||||
(count: number) => {
|
||||
if (count > 0) {
|
||||
;(this.$el as HTMLElement).style.setProperty(columnCountKey, count.toString())
|
||||
} else {
|
||||
;(this.$el as HTMLElement).style.removeProperty(columnCountKey)
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
@ -76,17 +80,13 @@ export default Vue.extend({
|
||||
&-tabs {
|
||||
flex-grow: 1;
|
||||
min-width: calc(
|
||||
var(--card-width) * var(--minimal-home-card-column) +
|
||||
var(--minimal-home-grid-gap) * (var(--minimal-home-card-column) - 1) + 2 *
|
||||
var(--minimal-home-grid-padding)
|
||||
var(--card-width) * var(--minimal-home-card-column) + var(--minimal-home-grid-gap) *
|
||||
(var(--minimal-home-card-column) - 1) + 2 * var(--minimal-home-grid-padding)
|
||||
);
|
||||
.minimal-home-tab {
|
||||
&-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(
|
||||
var(--minimal-home-card-column),
|
||||
var(--card-width)
|
||||
);
|
||||
grid-template-columns: repeat(var(--minimal-home-card-column), var(--card-width));
|
||||
gap: var(--minimal-home-grid-gap);
|
||||
padding: 0 var(--minimal-home-grid-padding);
|
||||
margin-bottom: 16px;
|
||||
|
||||
@ -5,17 +5,14 @@
|
||||
icon
|
||||
class="minimal-home-operations-refresh"
|
||||
title="刷新"
|
||||
@click="backToTop(); $emit('refresh')"
|
||||
@click="
|
||||
backToTop()
|
||||
$emit('refresh')
|
||||
"
|
||||
>
|
||||
<VIcon icon="mdi-refresh" :size="size" />
|
||||
</VButton>
|
||||
<VButton
|
||||
round
|
||||
icon
|
||||
class="minimal-home-operations-top"
|
||||
title="返回顶部"
|
||||
@click="backToTop"
|
||||
>
|
||||
<VButton round icon class="minimal-home-operations-top" title="返回顶部" @click="backToTop">
|
||||
<VIcon icon="mdi-arrow-up" :size="size" />
|
||||
</VButton>
|
||||
</div>
|
||||
|
||||
@ -25,13 +25,15 @@ export const component = defineComponentMetadata({
|
||||
name: 'minimalHome',
|
||||
displayName: '极简首页',
|
||||
urlInclude: homeUrls,
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.style],
|
||||
entry: () => {
|
||||
addComponentListener('minimalHome.columnCount', (count: number) => {
|
||||
document.documentElement.style.setProperty('--home-column-count-override', count.toString())
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'minimalHome.columnCount',
|
||||
(count: number) => {
|
||||
document.documentElement.style.setProperty('--home-column-count-override', count.toString())
|
||||
},
|
||||
true,
|
||||
)
|
||||
contentLoaded(async () => {
|
||||
const MinimalHome = await import('./MinimalHome.vue')
|
||||
const minimalHome = mountVueComponent(MinimalHome)
|
||||
|
||||
@ -2,4 +2,5 @@ import { OptionsOfMetadata } from '@/components/define'
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
import type { minimalHomeOptionsMetadata } from '.'
|
||||
|
||||
export const minimalHomeOptions = getComponentSettings<OptionsOfMetadata<typeof minimalHomeOptionsMetadata>>('minimalHome').options
|
||||
export const minimalHomeOptions =
|
||||
getComponentSettings<OptionsOfMetadata<typeof minimalHomeOptionsMetadata>>('minimalHome').options
|
||||
|
||||
@ -14,10 +14,7 @@ import { VideoCard } from '@/components/feeds/video-card'
|
||||
import VideoCardComponent from '@/components/feeds/VideoCard.vue'
|
||||
import { logError } from '@/core/utils/log'
|
||||
import { ascendingStringSort } from '@/core/utils/sort'
|
||||
import {
|
||||
VEmpty,
|
||||
ScrollTrigger,
|
||||
} from '@/ui'
|
||||
import { VEmpty, ScrollTrigger } from '@/ui'
|
||||
import MinimalHomeOperations from '../MinimalHomeOperations.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
@ -46,7 +43,10 @@ export default Vue.extend({
|
||||
try {
|
||||
this.error = false
|
||||
this.loading = true
|
||||
this.cards = lodash.uniqBy([...this.cards, ...await getVideoFeeds('video', this.lastID)], it => it.id)
|
||||
this.cards = lodash.uniqBy(
|
||||
[...this.cards, ...(await getVideoFeeds('video', this.lastID))],
|
||||
it => it.id,
|
||||
)
|
||||
} catch (error) {
|
||||
logError(error)
|
||||
this.error = true
|
||||
|
||||
@ -13,10 +13,7 @@ import { VideoCard } from '@/components/feeds/video-card'
|
||||
import VideoCardComponent from '@/components/feeds/VideoCard.vue'
|
||||
import { logError } from '@/core/utils/log'
|
||||
import { ascendingStringSort } from '@/core/utils/sort'
|
||||
import {
|
||||
VEmpty,
|
||||
VLoading,
|
||||
} from '@/ui'
|
||||
import { VEmpty, VLoading } from '@/ui'
|
||||
import { getTrendingVideos } from '../../trending'
|
||||
import MinimalHomeOperations from '../MinimalHomeOperations.vue'
|
||||
import { minimalHomeOptions } from '../options'
|
||||
|
||||
@ -3,9 +3,11 @@ import { getJson } from '@/core/ajax'
|
||||
/**
|
||||
* 封装一些 API 请求的通用行为, 使用者要定义 parseJson 方法将返回的 JSON 转换为数据数组, 会自动存到 this.items 里
|
||||
*/
|
||||
export const requestMixin = (config: {
|
||||
requestMethod?: (url: string) => Promise<any>
|
||||
} = {}) => {
|
||||
export const requestMixin = (
|
||||
config: {
|
||||
requestMethod?: (url: string) => Promise<any>
|
||||
} = {},
|
||||
) => {
|
||||
const { requestMethod = getJson } = config
|
||||
return Vue.extend({
|
||||
props: {
|
||||
@ -34,9 +36,10 @@ export const requestMixin = (config: {
|
||||
try {
|
||||
this.error = false
|
||||
this.loading = true
|
||||
this.items = this.parseJson(
|
||||
await requestMethod(this.api),
|
||||
).slice(0, this.itemLimit ?? Infinity)
|
||||
this.items = this.parseJson(await requestMethod(this.api)).slice(
|
||||
0,
|
||||
this.itemLimit ?? Infinity,
|
||||
)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.error = true
|
||||
@ -52,19 +55,18 @@ export const requestMixin = (config: {
|
||||
* 将 UI 常量放到 this.ui 上, 并在根元素上同步对应的 CSS var
|
||||
* @param variables UI 常量
|
||||
*/
|
||||
export const cssVariableMixin = (variables: Record<string, string | number>) => Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
ui: variables,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const element = this.$el as HTMLElement
|
||||
Object.entries(variables).forEach(
|
||||
([name, value]) => {
|
||||
export const cssVariableMixin = (variables: Record<string, string | number>) =>
|
||||
Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
ui: variables,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const element = this.$el as HTMLElement
|
||||
Object.entries(variables).forEach(([name, value]) => {
|
||||
const stringValue = typeof value === 'number' ? `${value}px` : value
|
||||
element.style.setProperty(`--${lodash.kebabCase(name)}`, stringValue)
|
||||
},
|
||||
)
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@ -11,10 +11,7 @@ export const component = defineComponentMetadata({
|
||||
style: () => import('./player-shadow.scss'),
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.video,
|
||||
],
|
||||
tags: [componentsTags.style, componentsTags.video],
|
||||
description: {
|
||||
'zh-CN': '为播放器添加主题色投影.',
|
||||
},
|
||||
|
||||
@ -4,11 +4,9 @@ export const component = defineComponentMetadata({
|
||||
name: 'elegantScrollbar',
|
||||
entry: none,
|
||||
displayName: '使用细滚动条',
|
||||
description: '使用浏览器的滚动条风格替代系统的滚动条, 不过 macOS 系统滚动条比浏览器做得好一些, 因此不建议 macOS 使用此功能.',
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
componentsTags.general,
|
||||
],
|
||||
description:
|
||||
'使用浏览器的滚动条风格替代系统的滚动条, 不过 macOS 系统滚动条比浏览器做得好一些, 因此不建议 macOS 使用此功能.',
|
||||
tags: [componentsTags.style, componentsTags.general],
|
||||
instantStyles: [
|
||||
{
|
||||
name: 'elegant-scrollbar',
|
||||
|
||||
@ -16,9 +16,13 @@ export const component = defineComponentMetadata({
|
||||
'zh-CN': '给脚本的侧栏设置垂直偏移量, 范围为 -35% ~ 40%',
|
||||
},
|
||||
entry: ({ metadata }) => {
|
||||
addComponentListener(`${metadata.name}.offset`, (value: number) => {
|
||||
document.body.style.setProperty('--be-sidebar-offset', `${value}%`)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
`${metadata.name}.offset`,
|
||||
(value: number) => {
|
||||
document.body.style.setProperty('--be-sidebar-offset', `${value}%`)
|
||||
},
|
||||
true,
|
||||
)
|
||||
},
|
||||
options: {
|
||||
offset: {
|
||||
|
||||
@ -5,9 +5,13 @@ export const component = defineComponentMetadata({
|
||||
name,
|
||||
entry: async ({ metadata }) => {
|
||||
const { addComponentListener } = await import('@/core/settings')
|
||||
addComponentListener(metadata.name, (value: boolean) => {
|
||||
document.body.classList.toggle('simplify-comment', value)
|
||||
}, true)
|
||||
addComponentListener(
|
||||
metadata.name,
|
||||
(value: boolean) => {
|
||||
document.body.classList.toggle('simplify-comment', value)
|
||||
},
|
||||
true,
|
||||
)
|
||||
},
|
||||
instantStyles: [
|
||||
{
|
||||
@ -29,7 +33,5 @@ export const component = defineComponentMetadata({
|
||||
|
||||
> 注: 关注和等级可以通过鼠标停留在头像上, 在弹出的资料卡小窗中查看.`.trim(),
|
||||
},
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
tags: [componentsTags.style],
|
||||
})
|
||||
|
||||
@ -75,13 +75,15 @@ const metadata: ComponentMetadata = {
|
||||
() => dqa('.proxy-box > div'),
|
||||
elements => elements.length > 0 || isNotHome,
|
||||
)
|
||||
return Object.fromEntries(categoryElements.map(it => ([
|
||||
it.id.replace(/^bili_/, ''),
|
||||
{
|
||||
displayName: it.querySelector('header .name')?.textContent?.trim() ?? '未知分区',
|
||||
defaultValue: false,
|
||||
},
|
||||
])))
|
||||
return Object.fromEntries(
|
||||
categoryElements.map(it => [
|
||||
it.id.replace(/^bili_/, ''),
|
||||
{
|
||||
displayName: it.querySelector('header .name')?.textContent?.trim() ?? '未知分区',
|
||||
defaultValue: false,
|
||||
},
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
const skipIds = ['推广']
|
||||
@ -100,24 +102,25 @@ const metadata: ComponentMetadata = {
|
||||
}
|
||||
return null
|
||||
}
|
||||
const entries = headers
|
||||
?.filter(element => !skipIds.includes(element.id))
|
||||
.map(element => {
|
||||
const container = getContainer(element) as HTMLElement
|
||||
const name = element.id
|
||||
if (container) {
|
||||
container.dataset.area = name
|
||||
return [
|
||||
name,
|
||||
{
|
||||
displayName: name,
|
||||
defaultValue: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter((it): it is [string, SimplifyHomeOption] => it !== null) ?? []
|
||||
const entries =
|
||||
headers
|
||||
?.filter(element => !skipIds.includes(element.id))
|
||||
.map(element => {
|
||||
const container = getContainer(element) as HTMLElement
|
||||
const name = element.id
|
||||
if (container) {
|
||||
container.dataset.area = name
|
||||
return [
|
||||
name,
|
||||
{
|
||||
displayName: name,
|
||||
defaultValue: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter((it): it is [string, SimplifyHomeOption] => it !== null) ?? []
|
||||
return Object.fromEntries(entries)
|
||||
})()
|
||||
const generatedSwitches: Record<string, unknown> = {}
|
||||
@ -142,12 +145,16 @@ const metadata: ComponentMetadata = {
|
||||
generatedSwitches[key] = option
|
||||
})
|
||||
options.simplifyOptions.switches = generatedSwitches
|
||||
const generatedStyles = Object.keys(generatedOptions).map(name => `
|
||||
const generatedStyles = Object.keys(generatedOptions)
|
||||
.map(name =>
|
||||
`
|
||||
body.simplifyHome-switch-${name} .bili-layout .bili-grid[data-area="${name}"],
|
||||
body.simplifyHome-switch-${name} .storey-box .proxy-box #bili_${name} {
|
||||
display: none !important;
|
||||
}
|
||||
`.trim()).join('\n')
|
||||
`.trim(),
|
||||
)
|
||||
.join('\n')
|
||||
addStyle(generatedStyles, 'simplify-home-generated')
|
||||
},
|
||||
}
|
||||
|
||||
@ -91,21 +91,19 @@ export const component = createSwitchOptions({
|
||||
displayName: '房间皮肤',
|
||||
},
|
||||
},
|
||||
})(
|
||||
{
|
||||
name: 'simplifyLiveroom',
|
||||
displayName: '简化直播间',
|
||||
entry: styledComponentEntry(() => import('./live.scss'), async () => {
|
||||
})({
|
||||
name: 'simplifyLiveroom',
|
||||
displayName: '简化直播间',
|
||||
entry: styledComponentEntry(
|
||||
() => import('./live.scss'),
|
||||
async () => {
|
||||
const { setupSkinSimplify } = await import('./skin')
|
||||
setupSkinSimplify()
|
||||
}),
|
||||
description: {
|
||||
'zh-CN': '隐藏直播间中各种不需要的内容.',
|
||||
},
|
||||
tags: [
|
||||
componentsTags.live,
|
||||
componentsTags.style,
|
||||
],
|
||||
urlInclude: liveUrls,
|
||||
),
|
||||
description: {
|
||||
'zh-CN': '隐藏直播间中各种不需要的内容.',
|
||||
},
|
||||
)
|
||||
tags: [componentsTags.live, componentsTags.style],
|
||||
urlInclude: liveUrls,
|
||||
})
|
||||
|
||||
@ -2,11 +2,15 @@ import { addComponentListener } from '@/core/settings'
|
||||
import { select } from '@/core/spin-query'
|
||||
|
||||
export const setupSkinSimplify = async () => {
|
||||
addComponentListener('simplifyLiveroom.switch-skin', async (disable: boolean) => {
|
||||
const skinCss = await select('#skin-css') as HTMLStyleElement
|
||||
if (!skinCss) {
|
||||
return
|
||||
}
|
||||
skinCss.media = disable ? 'none' : 'all'
|
||||
}, true)
|
||||
addComponentListener(
|
||||
'simplifyLiveroom.switch-skin',
|
||||
async (disable: boolean) => {
|
||||
const skinCss = (await select('#skin-css')) as HTMLStyleElement
|
||||
if (!skinCss) {
|
||||
return
|
||||
}
|
||||
skinCss.media = disable ? 'none' : 'all'
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user