mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Add blackboard
This commit is contained in:
parent
eac68c2866
commit
3e6bc26ba4
12
registry/dist/components/style/home-redesign/fresh.js
vendored
Normal file
12
registry/dist/components/style/home-redesign/fresh.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="home-redesign-base">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default Vue.extend({
|
||||
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
|
||||
.home-redesign-base {
|
||||
--home-base-color: #fff;
|
||||
--home-background-color: #fff;
|
||||
--home-color: #000;
|
||||
--home-max-width: var(--home-max-width-override, 1440px);
|
||||
--home-card-radius: 12px;
|
||||
--home-card-shadow: 0 0 0 1px #8881, 0 4px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
background-color: var(--home-base-color);
|
||||
color: var(--home-color);
|
||||
font-size: 12px;
|
||||
min-height: 100vh;
|
||||
line-height: normal;
|
||||
@include v-center();
|
||||
|
||||
body.dark & {
|
||||
--home-base-color: #181818;
|
||||
--home-background-color: #282828;
|
||||
--home-color: #eee;
|
||||
--home-card-shadow: 0 0 0 1px #8882, 0 4px 12px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<HomeRedesignBase>
|
||||
<div class="fresh-home">
|
||||
<div class="fresh-home-content-layout">
|
||||
<FreshLayoutItem
|
||||
v-for="layout of layouts"
|
||||
:key="layout.name"
|
||||
:item="layout"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</HomeRedesignBase>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import HomeRedesignBase from '../HomeRedesignBase.vue'
|
||||
import FreshLayoutItem from './FreshLayoutItem.vue'
|
||||
import { layouts } from './layouts/layouts'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
HomeRedesignBase,
|
||||
FreshLayoutItem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
layouts,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
|
||||
.fresh-home {
|
||||
padding: 24px;
|
||||
width: 100%;
|
||||
max-width: var(--home-max-width, unset);
|
||||
@include v-stretch();
|
||||
&-header {
|
||||
@include h-center();
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
&-title {
|
||||
color: var(--home-color);
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
}
|
||||
&-more {
|
||||
@include semibold();
|
||||
.be-icon {
|
||||
transition: .3s ease-out;
|
||||
margin-right: 6px;
|
||||
}
|
||||
&:hover .be-icon {
|
||||
transform: rotate(0.5turn);
|
||||
}
|
||||
}
|
||||
}
|
||||
&-content-layout {
|
||||
@include h-stretch();
|
||||
flex-wrap: wrap;
|
||||
gap: 12px 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div
|
||||
class="fresh-home-content-layout-item"
|
||||
:class="{
|
||||
grow: item.grow,
|
||||
linebreak: options.linebreak,
|
||||
}"
|
||||
>
|
||||
<component :is="item.component" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
import { FreshLayoutItemSettings } from './layouts/fresh-layout-item'
|
||||
|
||||
const options = getComponentSettings('freshHome').options as {
|
||||
layoutOptions: Record<string, FreshLayoutItemSettings>
|
||||
}
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
item: {
|
||||
required: true,
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: options.layoutOptions[this.item.name] ?? {},
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.fresh-home {
|
||||
&-content-layout-item {
|
||||
flex: 0 0 auto;
|
||||
&.linebreak {
|
||||
flex: 1 0 100%;
|
||||
}
|
||||
&.grow {
|
||||
flex: 1 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
registry/lib/components/style/home-redesign/fresh/index.ts
Normal file
34
registry/lib/components/style/home-redesign/fresh/index.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { ComponentMetadata } from '@/components/types'
|
||||
import { contentLoaded } from '@/core/life-cycle'
|
||||
import { mountVueComponent } from '@/core/utils'
|
||||
import { homeUrls } from '../urls'
|
||||
|
||||
export const component: ComponentMetadata = {
|
||||
name: 'freshHome',
|
||||
displayName: '清爽首页',
|
||||
description: '使用重新设计的清爽风格首页替换原本的首页.',
|
||||
urlInclude: homeUrls,
|
||||
tags: [
|
||||
componentsTags.style,
|
||||
],
|
||||
entry: () => {
|
||||
contentLoaded(async () => {
|
||||
const FreshHome = await import('./FreshHome.vue')
|
||||
const freshHome = mountVueComponent(FreshHome)
|
||||
document.body.appendChild(freshHome.$el)
|
||||
})
|
||||
},
|
||||
options: {
|
||||
layoutOptions: {
|
||||
displayName: '版块设置',
|
||||
defaultValue: {},
|
||||
hidden: true,
|
||||
},
|
||||
},
|
||||
instantStyles: [
|
||||
{
|
||||
name: 'fresh-home-hide-original',
|
||||
style: () => import('../hide-original.scss'),
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div class="fresh-home-blackboard">
|
||||
<div class="fresh-home-header">
|
||||
<div class="fresh-home-header-title">
|
||||
活动
|
||||
</div>
|
||||
<a class="fresh-home-header-more" href="https://www.bilibili.com/blackboard/x/act_list/" target="_blank">
|
||||
<VButton round>
|
||||
<VIcon icon="mdi-dots-horizontal" :size="18"></VIcon>
|
||||
更多
|
||||
</VButton>
|
||||
</a>
|
||||
</div>
|
||||
<input
|
||||
v-for="(b, i) of blackboards"
|
||||
:id="'blackboard' + i"
|
||||
:key="i"
|
||||
class="fresh-home-blackboard-radio"
|
||||
type="radio"
|
||||
name="blackboard"
|
||||
:checked="i === 0"
|
||||
:data-index="i"
|
||||
/>
|
||||
<div class="fresh-home-blackboard-cards">
|
||||
<a
|
||||
v-for="(b, i) of blackboards"
|
||||
:key="i"
|
||||
class="fresh-home-blackboard-card"
|
||||
target="_blank"
|
||||
:href="b.url"
|
||||
:title="b.title"
|
||||
>
|
||||
<DpiImage
|
||||
class="fresh-home-blackboard-card-image"
|
||||
:src="b.imageUrl"
|
||||
:alt="b.title"
|
||||
:size="{ width: 500, height: 250 }"
|
||||
:intersection="{ root: cardsContainer }"
|
||||
/>
|
||||
<div class="fresh-home-blackboard-card-title" :title="b.title">
|
||||
{{ b.title }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="fresh-home-blackboard-jump-dots">
|
||||
<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 { getBlackboards } from './api'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
VButton,
|
||||
VIcon,
|
||||
DpiImage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
blackboards: [],
|
||||
timer: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
cardsContainer() {
|
||||
return this.$el.querySelector('.fresh-home-blackboard-cards')
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
const blackboards = await getBlackboards()
|
||||
this.blackboards = blackboards.filter(b => !b.isAd)
|
||||
},
|
||||
mounted() {
|
||||
const radioClass = 'fresh-home-blackboard-radio'
|
||||
this.timer = window.setInterval(() => {
|
||||
if (!document.hasFocus() || this.$el.matches(':hover')) {
|
||||
return
|
||||
}
|
||||
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
|
||||
}, 5000)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.timer) {
|
||||
window.clearInterval(this.timer)
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
|
||||
$max-card-count: 16;
|
||||
.fresh-home {
|
||||
&-blackboard {
|
||||
position: relative;
|
||||
&,
|
||||
& * {
|
||||
transition: .2s ease-out;
|
||||
}
|
||||
&-cards {
|
||||
display: flex;
|
||||
--blackboard-width: 350px;
|
||||
--blackboard-height: 250px;
|
||||
--image-height: 197px;
|
||||
width: var(--blackboard-width);
|
||||
height: var(--blackboard-height);
|
||||
box-shadow: var(--home-card-shadow);
|
||||
border-radius: var(--home-card-radius);
|
||||
background-color: var(--home-background-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
&-card {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: block;
|
||||
transition: 0.8s cubic-bezier(0.44, 0.29, 0.13, 1);
|
||||
color: inherit;
|
||||
body.dark & {
|
||||
color: inherit !important;
|
||||
}
|
||||
&-image {
|
||||
width: 100%;
|
||||
height: var(--image-height);
|
||||
object-fit: fill;
|
||||
display: block;
|
||||
border-radius: 12px;
|
||||
transition-duration: inherit;
|
||||
}
|
||||
&-title {
|
||||
$bottom: 16px;
|
||||
position: absolute;
|
||||
bottom: $bottom;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0 16px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: calc(var(--blackboard-height) - var(--image-height) - #{$bottom});
|
||||
border-radius: 14px;
|
||||
max-width: var(--blackboard-width);
|
||||
box-sizing: border-box;
|
||||
@include single-line();
|
||||
}
|
||||
}
|
||||
&-radio {
|
||||
display: none;
|
||||
@for $i from 1 to $max-card-count {
|
||||
&:checked:nth-of-type(#{$i})
|
||||
~ .fresh-home-blackboard-jump-dots
|
||||
label:nth-child(#{$i})
|
||||
.fresh-home-blackboard-jump-dot {
|
||||
background-color: var(--theme-color);
|
||||
width: 40px;
|
||||
}
|
||||
&:checked:nth-of-type(#{$i}) ~ .fresh-home-blackboard-cards .fresh-home-blackboard-card {
|
||||
transform: translateX(calc(-1 * #{$i - 1} * var(--blackboard-width))) scale(0.9);
|
||||
&:nth-of-type(#{$i}) {
|
||||
transform: translateX(calc(-1 * #{$i - 1} * var(--blackboard-width)));
|
||||
img {
|
||||
border-radius: var(--home-card-radius) var(--home-card-radius) 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&-jump-dots {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translateX(-50%);
|
||||
@include h-center();
|
||||
label {
|
||||
display: block;
|
||||
padding: 8px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&-jump-dot {
|
||||
background-color: #8884;
|
||||
box-sizing: border-box;
|
||||
width: 20px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,24 @@
|
||||
import { getJson } from '@/core/ajax'
|
||||
|
||||
export interface Blackboard {
|
||||
url: string
|
||||
title: string
|
||||
isAd: boolean
|
||||
imageUrl: string
|
||||
}
|
||||
export const getBlackboards = async (): Promise<Blackboard[]> => {
|
||||
const locId = 4694
|
||||
const api = `https://api.bilibili.com/x/web-show/res/locs?pf=0&ids=${locId}`
|
||||
const { code, message, data } = await getJson(api)
|
||||
if (code !== 0) {
|
||||
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))
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
import { FreshLayoutItem } from '../fresh-layout-item'
|
||||
|
||||
export const blackboard: FreshLayoutItem = {
|
||||
name: 'blackboard',
|
||||
displayName: '活动',
|
||||
component: () => import('./Blackboard.vue').then(m => m.default),
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
import { Executable, VueModule, WithName } from '@/core/common-types'
|
||||
|
||||
export interface FreshLayoutItem extends WithName {
|
||||
component: Executable<VueModule>
|
||||
grow?: boolean
|
||||
}
|
||||
export interface FreshLayoutItemSettings {
|
||||
name: string
|
||||
linebreak: boolean
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
import { registerAndGetData } from '@/plugins/data'
|
||||
import { blackboard } from './blackboard/blackboard'
|
||||
|
||||
const builtInLayouts = [
|
||||
blackboard,
|
||||
]
|
||||
export const [layouts] = registerAndGetData('homeRedesign.fresh.layouts', [...builtInLayouts])
|
||||
@ -0,0 +1,18 @@
|
||||
.international-home > :not(.international-header),
|
||||
.international-header .b-wrap,
|
||||
.international-footer,
|
||||
#app > .bili-wrapper,
|
||||
#app > .elevator-module,
|
||||
#app > .bili-header-m.stardust-common > .bili-wrapper,
|
||||
.bili-header-m .head-banner .head-content .head-logo,
|
||||
#i_cecream .bili-header__channel,
|
||||
#i_cecream > :not(.bili-header) {
|
||||
position: fixed;
|
||||
visibility: hidden;
|
||||
top: 200vh;
|
||||
left: 0;
|
||||
height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
4
registry/lib/components/style/home-redesign/urls.ts
Normal file
4
registry/lib/components/style/home-redesign/urls.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const homeUrls = [
|
||||
/^https:\/\/www\.bilibili\.com\/$/,
|
||||
/^https:\/\/www\.bilibili\.com\/index\.html$/,
|
||||
]
|
||||
@ -1,4 +1,6 @@
|
||||
let eventAttached = false
|
||||
|
||||
// FIXME: 需要重构, 不要直接对具体组件有行为依赖
|
||||
export const disableProfilePopup = () => {
|
||||
if (document.URL.replace(window.location.search, '') === 'https://t.bilibili.com/') {
|
||||
(async () => {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<img
|
||||
v-bind="$attrs"
|
||||
:width="width"
|
||||
:height="height"
|
||||
:srcset="srcset"
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
@mixin shadow {
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
// box-shadow: #0002 0 1px 10px 1px;
|
||||
body.dark & {
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
@mixin h-center($gap: 0) {
|
||||
display: flex;
|
||||
@ -69,14 +72,12 @@
|
||||
background-color: #fff;
|
||||
color: black;
|
||||
border-radius: $radius;
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid #8882;
|
||||
box-sizing: border-box;
|
||||
// box-shadow: rgba(0, 0, 0, 0.12) 0 4px 8px 0px;
|
||||
@include shadow();
|
||||
body.dark & {
|
||||
background-color: #282828;
|
||||
color: #eee;
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
@mixin popup($radius: 8px) {
|
||||
@ -119,6 +120,9 @@
|
||||
stroke: #eee;
|
||||
}
|
||||
}
|
||||
@mixin semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
@mixin default-background-color {
|
||||
background-color: #fff;
|
||||
body.dark & {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user