广告修改
This commit is contained in:
@@ -105,6 +105,11 @@ type AdvitiseData struct {
|
||||
TitleList []Advertisement `json:"titleList"`
|
||||
PlayList []Advertisement `json:"playList"`
|
||||
PauseyList []Advertisement `json:"pauseyList"`
|
||||
// 本站后台(webhg2api)的字段名:横幅 / 播放页小图标 / 首页小图标
|
||||
VideoTopList []Advertisement `json:"videoTopList"`
|
||||
VideoDownList []Advertisement `json:"videoDownList"`
|
||||
AppInfoAList []Advertisement `json:"appInfoAList"`
|
||||
AppInfoBList []Advertisement `json:"appInfoBList"`
|
||||
}
|
||||
|
||||
// Advertisement 对应 swagger proxy.AdvitiseInfo。
|
||||
|
||||
@@ -8,33 +8,35 @@ import (
|
||||
// AppConfigVM 注入全站页面的公共配置(字段名与接口 newAddressInfo / seoInfo 对齐)。
|
||||
type AppConfigVM struct {
|
||||
// Config 为 data.config 原样字段(页脚社交等优先用此对象)。
|
||||
Config ConfigInfo `json:"config"`
|
||||
ForeverURLAddr string `json:"foreverUrlAddr"`
|
||||
NewURLAddr string `json:"newUrlAddr"`
|
||||
NewURLAddr1 string `json:"newUrlAddr1"`
|
||||
NewURLAddr2 string `json:"newUrlAddr2"`
|
||||
GmailAddr string `json:"gmailAddr"`
|
||||
QQ string `json:"qq"`
|
||||
TGGroup string `json:"tgGroup"`
|
||||
Telegram string `json:"telegram"`
|
||||
TelegramAdd string `json:"telegramAdd"`
|
||||
PotaoGroup string `json:"potaoGroup"`
|
||||
CustomerServiceHost string `json:"customerServiceHost"`
|
||||
AppAddr string `json:"appAddr"`
|
||||
OfficialAppAddr string `json:"officialAppAddr"`
|
||||
PDFAddr string `json:"pdfAddr"`
|
||||
TwitterAddr string `json:"twitterAddr"`
|
||||
GitAddr string `json:"gitAddr"`
|
||||
FreeVPN string `json:"freeVPN"`
|
||||
SeoInfo SeoInfo `json:"seoInfo,omitempty"`
|
||||
SeoNavInfo SeoNavInfo `json:"seoNavInfo,omitempty"`
|
||||
NavPageList []NavPageItem `json:"navPageList,omitempty"`
|
||||
Advitise AdvitiseData `json:"advitise"`
|
||||
DetailTopList []Advertisement `json:"detailTopList,omitempty"`
|
||||
NineGridList []Advertisement `json:"nineGridList,omitempty"`
|
||||
DetailBannerList []Advertisement `json:"detailbannerList,omitempty"`
|
||||
BottomBanner []Advertisement `json:"bottomBanner,omitempty"`
|
||||
DialogList []Advertisement `json:"dialogList,omitempty"`
|
||||
Config ConfigInfo `json:"config"`
|
||||
ForeverURLAddr string `json:"foreverUrlAddr"`
|
||||
NewURLAddr string `json:"newUrlAddr"`
|
||||
NewURLAddr1 string `json:"newUrlAddr1"`
|
||||
NewURLAddr2 string `json:"newUrlAddr2"`
|
||||
GmailAddr string `json:"gmailAddr"`
|
||||
QQ string `json:"qq"`
|
||||
TGGroup string `json:"tgGroup"`
|
||||
Telegram string `json:"telegram"`
|
||||
TelegramAdd string `json:"telegramAdd"`
|
||||
PotaoGroup string `json:"potaoGroup"`
|
||||
CustomerServiceHost string `json:"customerServiceHost"`
|
||||
AppAddr string `json:"appAddr"`
|
||||
OfficialAppAddr string `json:"officialAppAddr"`
|
||||
PDFAddr string `json:"pdfAddr"`
|
||||
TwitterAddr string `json:"twitterAddr"`
|
||||
GitAddr string `json:"gitAddr"`
|
||||
FreeVPN string `json:"freeVPN"`
|
||||
SeoInfo SeoInfo `json:"seoInfo,omitempty"`
|
||||
SeoNavInfo SeoNavInfo `json:"seoNavInfo,omitempty"`
|
||||
NavPageList []NavPageItem `json:"navPageList,omitempty"`
|
||||
Advitise AdvitiseData `json:"advitise"`
|
||||
// 网页只用后台「站点」的 5 个广告位:
|
||||
// 弹窗 / 9宫格(弹窗广告后弹出)/ 详情横幅 / 播放页小图标 / 首页小图标
|
||||
DialogList []Advertisement `json:"dialogList,omitempty"`
|
||||
NineGridList []Advertisement `json:"nineGridList,omitempty"`
|
||||
DetailBannerList []Advertisement `json:"detailbannerList,omitempty"`
|
||||
AList []Advertisement `json:"AList,omitempty"`
|
||||
BList []Advertisement `json:"BList,omitempty"`
|
||||
}
|
||||
|
||||
// BuildAppConfigVM 从上游配置组装前端可用字段;社交/地址优先取 data.config。
|
||||
@@ -65,11 +67,12 @@ func BuildAppConfigVM(info *ConfigInfoResp) AppConfigVM {
|
||||
FreeVPN: sanitizeURL(cfg.FreeVPN),
|
||||
NavPageList: buildNavPageList(info.NavPageList),
|
||||
Advitise: info.Advitise,
|
||||
DetailTopList: buildAdvertisementList(info.Advitise.DetailTopList),
|
||||
NineGridList: buildAdvertisementList(info.Advitise.NineGridList),
|
||||
DetailBannerList: buildAdvertisementList(info.Advitise.DetailBannerList),
|
||||
BottomBanner: buildAdvertisementList(info.Advitise.BottomBanner),
|
||||
DialogList: buildAdvertisementList(info.Advitise.DialogList),
|
||||
NineGridList: buildAdvertisementList(info.Advitise.NineGridList),
|
||||
// 本站后台用 videoTopList / appInfoAList / appInfoBList;兼容 detailbannerList / AList / BList 命名
|
||||
DetailBannerList: firstAdvertisementList(info.Advitise.VideoTopList, info.Advitise.DetailBannerList),
|
||||
AList: firstAdvertisementList(info.Advitise.AppInfoAList, info.Advitise.AList),
|
||||
BList: firstAdvertisementList(info.Advitise.AppInfoBList, info.Advitise.BList),
|
||||
SeoInfo: SeoInfo{
|
||||
Title: strings.TrimSpace(info.SeoInfo.Title),
|
||||
Description: strings.TrimSpace(info.SeoInfo.Description),
|
||||
@@ -142,20 +145,14 @@ func buildAdvertisementList(list []Advertisement) []Advertisement {
|
||||
return out
|
||||
}
|
||||
|
||||
// NineGridRow 按首页设计每行返回两个 banner,超出当前行时返回空切片。
|
||||
func (c AppConfigVM) NineGridRow(row int) []Advertisement {
|
||||
if row < 0 {
|
||||
return nil
|
||||
// firstAdvertisementList 返回第一个有可用广告的列表(按字段优先级)。
|
||||
func firstAdvertisementList(lists ...[]Advertisement) []Advertisement {
|
||||
for _, list := range lists {
|
||||
if built := buildAdvertisementList(list); len(built) > 0 {
|
||||
return built
|
||||
}
|
||||
}
|
||||
start := row * 2
|
||||
if start >= len(c.NineGridList) {
|
||||
return nil
|
||||
}
|
||||
end := start + 2
|
||||
if end > len(c.NineGridList) {
|
||||
end = len(c.NineGridList)
|
||||
}
|
||||
return c.NineGridList[start:end]
|
||||
return nil
|
||||
}
|
||||
|
||||
// QRText 应用下载二维码及跳转地址:仅使用应用下载地址 appAddr。
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package configser
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBuildAppConfigVMMapsSiteAdSlots(t *testing.T) {
|
||||
vm := BuildAppConfigVM(&ConfigInfoResp{
|
||||
Advitise: AdvitiseData{
|
||||
DialogList: []Advertisement{{ID: "dialog", Images: "https://cdn.example.com/dialog.gif"}},
|
||||
NineGridList: []Advertisement{{ID: "grid", Images: "https://cdn.example.com/grid.gif"}, {ID: "grid-empty", Images: " "}},
|
||||
VideoTopList: []Advertisement{
|
||||
{ID: " top ", Images: " https://cdn.example.com/top.gif ", Link: " https://example.com/top "},
|
||||
{ID: "top-empty", Images: " "},
|
||||
},
|
||||
DetailBannerList: []Advertisement{{ID: "legacy-banner", Images: "https://cdn.example.com/legacy.gif"}},
|
||||
AppInfoAList: []Advertisement{{ID: "a", Images: "https://cdn.example.com/a.gif"}},
|
||||
AList: []Advertisement{{ID: "legacy-a", Images: "https://cdn.example.com/legacy-a.gif"}},
|
||||
BList: []Advertisement{{ID: "b", Images: "https://cdn.example.com/b.gif"}},
|
||||
},
|
||||
})
|
||||
|
||||
if len(vm.DialogList) != 1 || vm.DialogList[0].ID != "dialog" {
|
||||
t.Fatalf("DialogList = %#v", vm.DialogList)
|
||||
}
|
||||
if len(vm.NineGridList) != 1 || vm.NineGridList[0].ID != "grid" {
|
||||
t.Fatalf("NineGridList = %#v, want images-only items", vm.NineGridList)
|
||||
}
|
||||
// 详情横幅优先本站后台字段 videoTopList,并清洗空格 / 过滤无图
|
||||
if len(vm.DetailBannerList) != 1 || vm.DetailBannerList[0].ID != "top" || vm.DetailBannerList[0].Link != "https://example.com/top" {
|
||||
t.Fatalf("DetailBannerList = %#v", vm.DetailBannerList)
|
||||
}
|
||||
// 播放页小图标优先 appInfoAList;首页小图标无 appInfoBList 时回退 BList
|
||||
if len(vm.AList) != 1 || vm.AList[0].ID != "a" {
|
||||
t.Fatalf("AList = %#v", vm.AList)
|
||||
}
|
||||
if len(vm.BList) != 1 || vm.BList[0].ID != "b" {
|
||||
t.Fatalf("BList = %#v", vm.BList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildAppConfigVMFallsBackToLegacyBannerField(t *testing.T) {
|
||||
vm := BuildAppConfigVM(&ConfigInfoResp{
|
||||
Advitise: AdvitiseData{DetailBannerList: []Advertisement{{ID: "banner", Images: "https://cdn.example.com/banner.gif"}}},
|
||||
})
|
||||
if len(vm.DetailBannerList) != 1 || vm.DetailBannerList[0].ID != "banner" {
|
||||
t.Fatalf("DetailBannerList = %#v, want detailbannerList fallback", vm.DetailBannerList)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* 小方块推荐(首页小图标 / 播放页小图标):一排方形图标 + 名称,放不下时横向滑动 */
|
||||
.app-icons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 16px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.app-icons__label {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.app-icons__row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
overflow-x: auto;
|
||||
overscroll-behavior-x: contain;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.app-icons__row::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-icons__item {
|
||||
flex: 0 0 auto;
|
||||
width: 96px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.app-icons__img {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
border-radius: 16px;
|
||||
background: #232328;
|
||||
}
|
||||
|
||||
.app-icons__name {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.app-icons {
|
||||
gap: 6px;
|
||||
padding: 12px var(--h5-gutter, 16px);
|
||||
}
|
||||
|
||||
.app-icons__row {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.app-icons__item {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.app-icons__img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
.app-icons__name {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/* 九宫格弹窗:深色模糊遮罩 + 4 列应用图标 + 底部关闭按钮(对齐 huangguocg.com) */
|
||||
.nine-grid-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1900;
|
||||
padding: 40px 24px;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
backdrop-filter: blur(12px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.nine-grid-mask.is-open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nine-grid-panel {
|
||||
width: min(520px, 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.nine-grid-list {
|
||||
width: 100%;
|
||||
max-height: 70vh;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 28px 24px;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.nine-grid-item {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nine-grid-item[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nine-grid-icon {
|
||||
width: 100%;
|
||||
max-width: 80px;
|
||||
aspect-ratio: 1;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.nine-grid-name {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nine-grid-close {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nine-grid-close svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.nine-grid-panel {
|
||||
width: min(360px, 100%);
|
||||
}
|
||||
|
||||
.nine-grid-list {
|
||||
gap: 20px 12px;
|
||||
}
|
||||
|
||||
.nine-grid-icon {
|
||||
max-width: 70px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.nine-grid-name {
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
/* 公共广告位统一规范
|
||||
* PC:双列,固定高 169
|
||||
* H5:单列两行,宽度 100%(占满所属内容容器),比例 343/98
|
||||
/* 公共广告位统一规范(详情横幅,素材 720×150)
|
||||
* PC:双列;H5:单列。均按 720:150 等比展示,避免裁切
|
||||
*/
|
||||
|
||||
.promo-rail {
|
||||
@@ -22,7 +21,7 @@
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
height: 169px;
|
||||
aspect-ratio: 720 / 150;
|
||||
border-radius: var(--radius-md);
|
||||
background: #232328;
|
||||
box-sizing: border-box;
|
||||
@@ -86,8 +85,7 @@
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
min-height: 98px;
|
||||
aspect-ratio: 343 / 98;
|
||||
aspect-ratio: 720 / 150;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--line-soft);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
(function () {
|
||||
// 弹窗广告队列结束(含没有 / 已关闭过)后通知九宫格弹窗:年龄确认 → 弹窗广告 → 九宫格
|
||||
function markDone() {
|
||||
if (window.__dialogAdDone) return;
|
||||
window.__dialogAdDone = true;
|
||||
document.dispatchEvent(new CustomEvent("dialogad:done"));
|
||||
}
|
||||
|
||||
var QUEUE_VERSION = "2";
|
||||
var DISMISSED_KEY = "dialogAdDismissed";
|
||||
var PROGRESS_KEY = "dialogAdProgress";
|
||||
var mask = document.querySelector("[data-dialog-ad]");
|
||||
var previousBodyOverflow = "";
|
||||
var hasDisplayedItem = false;
|
||||
if (!mask) return;
|
||||
if (!mask) return markDone();
|
||||
|
||||
var items = Array.prototype.slice.call(mask.querySelectorAll("[data-dialog-ad-item]"));
|
||||
if (!items.length) return;
|
||||
if (!items.length) return markDone();
|
||||
|
||||
var queueSignature =
|
||||
QUEUE_VERSION +
|
||||
@@ -119,7 +126,8 @@
|
||||
mask.classList.remove("is-open");
|
||||
mask.hidden = true;
|
||||
mask.setAttribute("hidden", "");
|
||||
document.body.style.overflow = previousBodyOverflow;
|
||||
document.body.style.overflow = previousBodyOverflow === "hidden" ? "" : previousBodyOverflow;
|
||||
markDone();
|
||||
}
|
||||
|
||||
function showWhenAgeGateAllows() {
|
||||
@@ -234,7 +242,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
if (isDismissed()) return;
|
||||
if (isDismissed()) return markDone();
|
||||
if (currentIndex >= items.length) {
|
||||
finishQueue();
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
(function () {
|
||||
// 九宫格弹窗(对齐 huangguocg.com):年龄确认 → 弹窗广告 → 九宫格。
|
||||
// 点任一应用 / 关闭按钮 / 空白处 / Esc 即关闭;同一会话内容不变时不再弹出。
|
||||
var DISMISSED_KEY = "gridAdDismissed";
|
||||
var mask = document.querySelector("[data-nine-grid]");
|
||||
if (!mask) return;
|
||||
|
||||
var items = Array.prototype.slice.call(mask.querySelectorAll("[data-nine-grid-item]"));
|
||||
if (!items.length) return;
|
||||
|
||||
var signature = JSON.stringify(
|
||||
items.map(function (item) {
|
||||
var image = item.querySelector("[data-nine-grid-src]");
|
||||
return [
|
||||
item.getAttribute("data-creative-id") || "",
|
||||
image ? image.getAttribute("data-nine-grid-src") : "",
|
||||
item.getAttribute("href") || "",
|
||||
];
|
||||
}),
|
||||
);
|
||||
|
||||
function readSession(key) {
|
||||
try {
|
||||
return window.sessionStorage.getItem(key) || "";
|
||||
} catch (error) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function writeSession(key, value) {
|
||||
try {
|
||||
window.sessionStorage.setItem(key, value);
|
||||
} catch (error) {
|
||||
// sessionStorage 不可用时仅本页关闭。
|
||||
}
|
||||
}
|
||||
|
||||
if (readSession(DISMISSED_KEY) === signature) return;
|
||||
|
||||
function waitForImage(image) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (image.complete && image.naturalWidth > 0 && image.src.indexOf("placeholder") === -1) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
var timeout = window.setTimeout(function () {
|
||||
cleanup();
|
||||
reject(new Error("image load timeout"));
|
||||
}, 12000);
|
||||
function cleanup() {
|
||||
window.clearTimeout(timeout);
|
||||
image.removeEventListener("load", handleLoad);
|
||||
image.removeEventListener("error", handleError);
|
||||
}
|
||||
function handleLoad() {
|
||||
cleanup();
|
||||
if (image.naturalWidth > 0) resolve();
|
||||
else reject(new Error("image decode failed"));
|
||||
}
|
||||
function handleError() {
|
||||
cleanup();
|
||||
reject(new Error("image load failed"));
|
||||
}
|
||||
image.addEventListener("load", handleLoad);
|
||||
image.addEventListener("error", handleError);
|
||||
});
|
||||
}
|
||||
|
||||
function loadIcon(image) {
|
||||
var source = image.getAttribute("data-nine-grid-src") || "";
|
||||
if (!source) return Promise.reject(new Error("image source is empty"));
|
||||
if (typeof window.processImage === "function") {
|
||||
return window.processImage(source, image).then(function (result) {
|
||||
if (!result) throw new Error("image decrypt failed");
|
||||
return waitForImage(image);
|
||||
});
|
||||
}
|
||||
image.src = source;
|
||||
return waitForImage(image);
|
||||
}
|
||||
|
||||
var opened = false;
|
||||
|
||||
function open() {
|
||||
if (opened) return;
|
||||
opened = true;
|
||||
mask.hidden = false;
|
||||
mask.removeAttribute("hidden");
|
||||
mask.classList.add("is-open");
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (!opened) return;
|
||||
opened = false;
|
||||
writeSession(DISMISSED_KEY, signature);
|
||||
mask.classList.remove("is-open");
|
||||
mask.hidden = true;
|
||||
mask.setAttribute("hidden", "");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
// 依次等待:年龄确认关闭 → 弹窗广告队列结束(没有弹窗广告时直接放行)
|
||||
function whenStartupReady(callback) {
|
||||
var ageGate = document.querySelector("[data-eighteen]");
|
||||
if (ageGate && ageGate.classList.contains("is-open")) {
|
||||
document.addEventListener(
|
||||
"eighteen:closed",
|
||||
function () {
|
||||
whenStartupReady(callback);
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
return;
|
||||
}
|
||||
var hasDialogAd = !!document.querySelector("[data-dialog-ad]");
|
||||
if (hasDialogAd && !window.__dialogAdDone) {
|
||||
document.addEventListener("dialogad:done", callback, { once: true });
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
// 只展示图标加载成功的应用;一个都没加载成功则不弹
|
||||
var ready = Promise.all(
|
||||
items.map(function (item) {
|
||||
var image = item.querySelector("[data-nine-grid-src]");
|
||||
if (!image) return Promise.resolve(false);
|
||||
return loadIcon(image)
|
||||
.then(function () {
|
||||
item.hidden = false;
|
||||
item.removeAttribute("hidden");
|
||||
return true;
|
||||
})
|
||||
.catch(function () {
|
||||
return false;
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
whenStartupReady(function () {
|
||||
ready.then(function (loaded) {
|
||||
if (loaded.some(Boolean)) open();
|
||||
});
|
||||
});
|
||||
|
||||
mask.addEventListener("click", function (event) {
|
||||
if (event.target === mask || event.target.closest("[data-nine-grid-close]") || event.target.closest("[data-nine-grid-item]")) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
mask.querySelector(".nine-grid-panel").addEventListener("click", function (event) {
|
||||
if (event.target === event.currentTarget) close();
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && opened) close();
|
||||
});
|
||||
})();
|
||||
@@ -1,8 +1,8 @@
|
||||
{{define "ads"}}
|
||||
{{/* 入参为 advitise.detailbannerList 的切片,字段与接口一致:images / link / title
|
||||
{{/* 详情横幅(后台位置 3,本站字段 videoTopList)的切片,字段:images / link / title
|
||||
类名避免 ads/ad-slot:夸克等浏览器内置广告拦截会隐藏这类选择器 */}}
|
||||
{{if .}}
|
||||
<link rel="stylesheet" href="/static/css/promo.css?v=1">
|
||||
<link rel="stylesheet" href="/static/css/promo.css?v=2">
|
||||
<section class="promo-rail" aria-label="推荐">
|
||||
{{range .}}
|
||||
<a class="promo-card" href="{{if .Link}}{{.Link}}{{else}}#{{end}}"{{if .Link}} target="_blank" rel="sponsored nofollow noopener"{{end}}>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{{define "appIcons"}}
|
||||
{{/* 小方块推荐:首页小图标(后台位置 13,BList)/ 播放页小图标(后台位置 12,AList)
|
||||
入参 dict "Items" 列表 "Label" 无障碍名称;类名避免 ads/ad-slot(夸克等浏览器会拦截) */}}
|
||||
{{if .Items}}
|
||||
<link rel="stylesheet" href="/static/css/appIcons.css?v=1">
|
||||
<section class="app-icons" aria-label="{{if .Label}}{{.Label}}{{else}}推荐{{end}}">
|
||||
<span class="app-icons__label">推广</span>
|
||||
<div class="app-icons__row">
|
||||
{{range .Items}}
|
||||
<a class="app-icons__item" href="{{if .Link}}{{.Link}}{{else}}#{{end}}"{{if .Link}} target="_blank" rel="sponsored nofollow noopener"{{end}} title="{{.Title}}">
|
||||
<img decoding="async" class="lazy app-icons__img" src="/static/images/placeholder.png?v=2" data-src="{{.Images}}" data-lazy-eager="1" alt="{{if .Title}}{{.Title}}{{else}}推荐{{end}}">
|
||||
<span class="app-icons__name">{{if .Title}}{{.Title}}{{else}}推荐{{end}}</span>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -51,6 +51,6 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<script defer src="/static/js/pages/dialogAd.js?v=9"></script>
|
||||
<script defer src="/static/js/pages/dialogAd.js?v=10"></script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
|
||||
{{template "eighteen" .}}
|
||||
{{template "dialogAd" .}}
|
||||
{{template "nineGridDialog" .}}
|
||||
{{template "toast" .}}
|
||||
<script defer src="/static/js/common/sharePage.js?v=1"></script>
|
||||
{{end}}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{{define "nineGridDialog"}}
|
||||
{{/* 九宫格弹窗:后台位置 2(nineGridList),在年龄确认、弹窗广告之后弹出 */}}
|
||||
{{if .appConfig.NineGridList}}
|
||||
<link rel="stylesheet" href="/static/css/nineGridDialog.css?v=1" />
|
||||
<div class="nine-grid-mask" id="nineGridDialog" data-nine-grid hidden>
|
||||
<div class="nine-grid-panel" role="dialog" aria-modal="true" aria-label="推荐应用">
|
||||
<div class="nine-grid-list">
|
||||
{{range $ad := .appConfig.NineGridList}}
|
||||
<a
|
||||
class="nine-grid-item"
|
||||
{{if $ad.Link}}href="{{$ad.Link}}" target="_blank" rel="sponsored nofollow noopener noreferrer"{{else}}aria-disabled="true"{{end}}
|
||||
data-nine-grid-item
|
||||
data-creative-id="{{$ad.ID}}"
|
||||
hidden
|
||||
>
|
||||
<img class="nine-grid-icon" src="/static/images/placeholder.png?v=2" data-nine-grid-src="{{$ad.Images}}" alt="{{$ad.Title}}" title="{{$ad.Title}}" decoding="async" />
|
||||
<span class="nine-grid-name">{{if $ad.Title}}{{$ad.Title}}{{else}}推荐应用{{end}}</span>
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<button class="nine-grid-close" type="button" data-nine-grid-close aria-label="关闭">
|
||||
<svg viewBox="0 0 36 36" width="36" height="36" aria-hidden="true"><circle cx="18" cy="18" r="16" fill="none" stroke="#fff" stroke-width="2"/><path d="M12.5 12.5l11 11M23.5 12.5l-11 11" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<script defer src="/static/js/pages/nineGridDialog.js?v=1"></script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -104,6 +104,8 @@
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
{{template "appIcons" dict "Items" .appConfig.BList "Label" "首页小图标"}}
|
||||
|
||||
<!-- 短剧标签:GET /api/app/playlet/tag/options → /tags/{slug}/ → tags.html -->
|
||||
<nav class="category" aria-label="短剧标签">
|
||||
<a class="category__item is-active" href="/list">全部</a>
|
||||
@@ -116,7 +118,6 @@
|
||||
homeConfigData:按接口顺序渲染;type 1短剧 / 2视频 / 3题材;
|
||||
名称为「热播榜」时用热播榜专用 UI;除 type=3 外下方插入 advitise.detailbannerList(每次 2 条)
|
||||
-->
|
||||
{{$adIdx := 0}}
|
||||
{{range $cfg := .homeConfigData}}
|
||||
{{if and (eq $cfg.Type 1) (eq $cfg.Name "热播榜") $.hotRankPlaylets}}
|
||||
<section class="block block--rank" data-id="{{$cfg.ID}}" data-type="{{$cfg.Type}}" aria-label="热播榜">
|
||||
@@ -158,8 +159,6 @@
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdx 2)}}
|
||||
{{$adIdx = add $adIdx 2}}
|
||||
|
||||
{{else if eq $cfg.Type 1}}
|
||||
<section class="block block--featured" data-id="{{$cfg.ID}}" data-type="{{$cfg.Type}}">
|
||||
@@ -187,8 +186,6 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</section>
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdx 2)}}
|
||||
{{$adIdx = add $adIdx 2}}
|
||||
|
||||
{{else if eq $cfg.Type 2}}
|
||||
<section class="block block--series" data-id="{{$cfg.ID}}" data-type="{{$cfg.Type}}">
|
||||
@@ -236,8 +233,6 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</section>
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdx 2)}}
|
||||
{{$adIdx = add $adIdx 2}}
|
||||
|
||||
{{else if eq $cfg.Type 3}}
|
||||
<section class="block block--topic" data-id="{{$cfg.ID}}" data-type="{{$cfg.Type}}">
|
||||
|
||||
@@ -56,8 +56,6 @@
|
||||
<h2 class="visually-hidden">短剧列表</h2>
|
||||
<p class="list-count">{{.listCount}}</p>
|
||||
{{if .list}}
|
||||
{{$adIdxPc := 0}}
|
||||
{{$adIdxH5 := 0}}
|
||||
{{$total := len .list}}
|
||||
<div class="grid--list">
|
||||
{{range $i, $item := .list}}
|
||||
@@ -68,21 +66,6 @@
|
||||
<h3 class="card__title"><a href="{{playURL $item.Slug $item.ID}}">{{if $item.PlayName}}{{$item.PlayName}}{{else}}{{$item.Title}}{{end}}</a></h3>
|
||||
<p class="card__meta card__meta--ep">{{template "cardEpChip" $item}}<span class="card__meta-tags">{{range $ti, $tag := cardTags $item}}{{if $ti}} {{end}}{{if $tag.URL}}<a href="{{$tag.URL}}" {{externalLinkAttrs $tag.URL}}>{{$tag.Name}}</a>{{else}}{{$tag.Name}}{{end}}{{end}}</span></p>
|
||||
</article>
|
||||
{{$n := add $i 1}}
|
||||
{{if and $.advitise $.advitise.DetailBannerList (lt $n $total)}}
|
||||
{{if eq (mod $n 12) 0}}
|
||||
<div class="list-mid-promo only-pc">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxPc 2)}}
|
||||
</div>
|
||||
{{$adIdxPc = add $adIdxPc 2}}
|
||||
{{end}}
|
||||
{{if eq (mod $n 6) 0}}
|
||||
<div class="list-mid-promo only-h5">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxH5 2)}}
|
||||
</div>
|
||||
{{$adIdxH5 = add $adIdxH5 2}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
@@ -92,9 +75,6 @@
|
||||
{{template "pagination" .}}
|
||||
</section>
|
||||
|
||||
<div class="list-bottom-promo">
|
||||
{{template "ads" (adSlice .advitise.DetailBannerList 2 2)}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
<h2 class="visually-hidden">{{if .configName}}{{.configName}}{{else}}精选短剧{{end}}作品列表</h2>
|
||||
<p class="list-count">{{.listCount}}</p>
|
||||
{{if .list}}
|
||||
{{$adIdxPc := 0}}
|
||||
{{$adIdxH5 := 0}}
|
||||
{{$total := len .list}}
|
||||
<div class="grid--list">
|
||||
{{range $i, $item := .list}}
|
||||
@@ -78,21 +76,6 @@
|
||||
<h3 class="card__title"><a href="{{playURL $item.Slug $item.ID}}">{{if $item.PlayName}}{{$item.PlayName}}{{else}}{{$item.Title}}{{end}}</a></h3>
|
||||
<p class="card__meta">{{range $ti, $tag := cardTags $item}}{{if $ti}} {{end}}{{if $tag.URL}}<a href="{{$tag.URL}}" {{externalLinkAttrs $tag.URL}}>{{$tag.Name}}</a>{{else}}{{$tag.Name}}{{end}}{{end}}</p>
|
||||
</article>
|
||||
{{$n := add $i 1}}
|
||||
{{if and $.advitise $.advitise.DetailBannerList (lt $n $total)}}
|
||||
{{if eq (mod $n 12) 0}}
|
||||
<div class="list-mid-promo only-pc">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxPc 2)}}
|
||||
</div>
|
||||
{{$adIdxPc = add $adIdxPc 2}}
|
||||
{{end}}
|
||||
{{if eq (mod $n 6) 0}}
|
||||
<div class="list-mid-promo only-h5">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxH5 2)}}
|
||||
</div>
|
||||
{{$adIdxH5 = add $adIdxH5 2}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "pagination" .}}
|
||||
@@ -102,9 +85,6 @@
|
||||
</section>
|
||||
|
||||
{{if .advitise}}
|
||||
<div class="list-bottom-promo">
|
||||
{{template "ads" (adSlice .advitise.DetailBannerList 0 2)}}
|
||||
</div>
|
||||
{{end}}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -60,8 +60,6 @@
|
||||
<h2 class="visually-hidden">{{if .configName}}{{.configName}}{{else}}精选视频{{end}}作品列表</h2>
|
||||
<p class="list-count">{{.listCount}}</p>
|
||||
{{if .list}}
|
||||
{{$adIdxPc := 0}}
|
||||
{{$adIdxH5 := 0}}
|
||||
{{$total := len .list}}
|
||||
<div class="grid--series-list">
|
||||
{{range $i, $item := .list}}
|
||||
@@ -76,21 +74,6 @@
|
||||
<h3 class="card__title"><a href="{{videoPlayURL $item.Slug $item.ID}}">{{$item.Title}}</a></h3>
|
||||
<p class="card__meta">{{if $item.CreatorName}}{{$item.CreatorName}}{{else}}{{range $ti, $k := $item.Keyworld}}{{if $ti}} {{end}}{{$k}}{{end}}{{end}}</p>
|
||||
</article>
|
||||
{{$n := add $i 1}}
|
||||
{{if and $.advitise $.advitise.DetailBannerList (lt $n $total)}}
|
||||
{{if eq (mod $n 12) 0}}
|
||||
<div class="series-list-promo only-pc">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxPc 2)}}
|
||||
</div>
|
||||
{{$adIdxPc = add $adIdxPc 2}}
|
||||
{{end}}
|
||||
{{if eq (mod $n 6) 0}}
|
||||
<div class="series-list-promo only-h5">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxH5 2)}}
|
||||
</div>
|
||||
{{$adIdxH5 = add $adIdxH5 2}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -100,11 +83,6 @@
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
{{if and .advitise .advitise.DetailBannerList}}
|
||||
<div class="list-bottom-promo">
|
||||
{{template "ads" (adSlice .advitise.DetailBannerList 2 2)}}
|
||||
</div>
|
||||
{{end}}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -302,8 +302,10 @@
|
||||
|
||||
{{template "playLinks" .}}
|
||||
|
||||
{{template "appIcons" dict "Items" .appConfig.AList "Label" "播放页小图标"}}
|
||||
|
||||
<div class="play-promo">
|
||||
{{if .advitise}}{{template "ads" (adSlice .advitise.DetailBannerList 0 2)}}{{end}}
|
||||
{{template "ads" (adSlice .appConfig.DetailBannerList 0 2)}}
|
||||
</div>
|
||||
|
||||
{{if .related}}
|
||||
@@ -401,7 +403,7 @@
|
||||
</section>
|
||||
|
||||
<div class="play-promo play-promo--bottom">
|
||||
{{if .advitise}}{{template "ads" (adSlice .advitise.DetailBannerList 2 2)}}{{end}}
|
||||
{{template "ads" (adSlice .appConfig.DetailBannerList 2 2)}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -50,8 +50,6 @@
|
||||
<h2 class="visually-hidden">{{if .tabTitle}}{{.tabTitle}}{{else}}热播榜{{end}}作品列表</h2>
|
||||
<p class="list-count">{{.listCount}}</p>
|
||||
{{if .list}}
|
||||
{{$adIdxPc := 0}}
|
||||
{{$adIdxH5 := 0}}
|
||||
{{$total := len .list}}
|
||||
<div class="grid--list">
|
||||
{{range $i, $item := .list}}
|
||||
@@ -69,21 +67,6 @@
|
||||
<h3 class="card__title"><a href="{{playURL $item.Slug $item.ID}}">{{if $item.PlayName}}{{$item.PlayName}}{{else}}{{$item.Title}}{{end}}</a></h3>
|
||||
<p class="card__meta">{{range $ti, $tag := cardTags $item}}{{if $ti}} {{end}}{{if $tag.URL}}<a href="{{$tag.URL}}" {{externalLinkAttrs $tag.URL}}>{{$tag.Name}}</a>{{else}}{{$tag.Name}}{{end}}{{end}}</p>
|
||||
</article>
|
||||
{{$n := add $i 1}}
|
||||
{{if and $.appConfig.DetailBannerList (lt $n $total)}}
|
||||
{{if eq (mod $n 12) 0}}
|
||||
<div class="list-mid-promo only-pc">
|
||||
{{template "ads" (adSlice $.appConfig.DetailBannerList $adIdxPc 2)}}
|
||||
</div>
|
||||
{{$adIdxPc = add $adIdxPc 2}}
|
||||
{{end}}
|
||||
{{if eq (mod $n 6) 0}}
|
||||
<div class="list-mid-promo only-h5">
|
||||
{{template "ads" (adSlice $.appConfig.DetailBannerList $adIdxH5 2)}}
|
||||
</div>
|
||||
{{$adIdxH5 = add $adIdxH5 2}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "pagination" .}}
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
<h2 class="visually-hidden">最近上新作品列表</h2>
|
||||
<p class="list-count">{{.listCount}}</p>
|
||||
{{if .list}}
|
||||
{{$adIdxPc := 0}}
|
||||
{{$adIdxH5 := 0}}
|
||||
{{$total := len .list}}
|
||||
<div class="grid--list">
|
||||
{{range $i, $item := .list}}
|
||||
@@ -58,21 +56,6 @@
|
||||
<h3 class="card__title"><a href="{{playURL $item.Slug $item.ID}}">{{if $item.PlayName}}{{$item.PlayName}}{{else}}{{$item.Title}}{{end}}</a></h3>
|
||||
<p class="card__meta">{{range $ti, $tag := cardTags $item}}{{if $ti}} {{end}}{{if $tag.URL}}<a href="{{$tag.URL}}" {{externalLinkAttrs $tag.URL}}>{{$tag.Name}}</a>{{else}}{{$tag.Name}}{{end}}{{end}}</p>
|
||||
</article>
|
||||
{{$n := add $i 1}}
|
||||
{{if and $.appConfig.DetailBannerList (lt $n $total)}}
|
||||
{{if eq (mod $n 12) 0}}
|
||||
<div class="list-mid-promo only-pc">
|
||||
{{template "ads" (adSlice $.appConfig.DetailBannerList $adIdxPc 2)}}
|
||||
</div>
|
||||
{{$adIdxPc = add $adIdxPc 2}}
|
||||
{{end}}
|
||||
{{if eq (mod $n 6) 0}}
|
||||
<div class="list-mid-promo only-h5">
|
||||
{{template "ads" (adSlice $.appConfig.DetailBannerList $adIdxH5 2)}}
|
||||
</div>
|
||||
{{$adIdxH5 = add $adIdxH5 2}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "pagination" .}}
|
||||
|
||||
@@ -57,8 +57,6 @@
|
||||
<h2 class="visually-hidden">剧集与动画作品列表</h2>
|
||||
<p class="list-count">{{.listCount}}</p>
|
||||
{{if .list}}
|
||||
{{$adIdxPc := 0}}
|
||||
{{$adIdxH5 := 0}}
|
||||
{{$total := len .list}}
|
||||
<div class="grid--series-list">
|
||||
{{range $i, $item := .list}}
|
||||
@@ -75,21 +73,6 @@
|
||||
<h3 class="card__title"><a href="{{videoPlayURL $item.Slug $item.ID}}">{{$item.Title}}</a></h3>
|
||||
<p class="card__meta">{{range $ti, $t := $item.TopicNames}}{{if $ti}} {{end}}{{$t}}{{else}}{{$item.CreatorName}}{{end}}</p>
|
||||
</article>
|
||||
{{$n := add $i 1}}
|
||||
{{if and $.advitise $.advitise.DetailBannerList (lt $n $total)}}
|
||||
{{if eq (mod $n 8) 0}}
|
||||
<div class="series-list-promo only-pc">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxPc 2)}}
|
||||
</div>
|
||||
{{$adIdxPc = add $adIdxPc 2}}
|
||||
{{end}}
|
||||
{{if eq (mod $n 4) 0}}
|
||||
<div class="series-list-promo only-h5">
|
||||
{{template "ads" (adSlice $.advitise.DetailBannerList $adIdxH5 2)}}
|
||||
</div>
|
||||
{{$adIdxH5 = add $adIdxH5 2}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -99,11 +82,6 @@
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
{{if and .advitise .advitise.DetailBannerList}}
|
||||
<div class="list-bottom-promo">
|
||||
{{template "ads" (adSlice .advitise.DetailBannerList 2 2)}}
|
||||
</div>
|
||||
{{end}}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -177,8 +177,10 @@
|
||||
|
||||
{{template "playLinks" .}}
|
||||
|
||||
{{template "appIcons" dict "Items" .appConfig.AList "Label" "播放页小图标"}}
|
||||
|
||||
<div class="play-promo">
|
||||
{{if .advitise}}{{template "ads" (adSlice .advitise.DetailBannerList 0 2)}}{{end}}
|
||||
{{template "ads" (adSlice .appConfig.DetailBannerList 0 2)}}
|
||||
</div>
|
||||
|
||||
<section class="play-dual" aria-label="推荐与热榜">
|
||||
@@ -251,7 +253,7 @@
|
||||
</section>
|
||||
|
||||
<div class="play-promo play-promo--bottom">
|
||||
{{if .advitise}}{{template "ads" (adSlice .advitise.DetailBannerList 2 2)}}{{end}}
|
||||
{{template "ads" (adSlice .appConfig.DetailBannerList 2 2)}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user