删除福利应用

This commit is contained in:
谢宇宁
2026-10-28 16:20:38 +07:00
parent 1a4718176d
commit 4e98b85fd8
18 changed files with 17 additions and 1090 deletions
-23
View File
@@ -1,23 +0,0 @@
package web
import (
"videoweb/app/service/applistser"
"github.com/gin-gonic/gin"
)
// Application 福利应用页 SSR:拉取 /api/app/applist/list。
func Application(c *gin.Context) {
raw := applistser.FetchListOrEmpty(c, 0)
vm := applistser.BuildPageVM(raw)
data := gin.H{
"title": "福利应用",
"pageName": "应用推荐",
"navActive": "application",
"categories": vm.Categories,
}
if len(vm.Categories) == 0 {
setNoIndex(data, true)
}
HTMLOK(c, "application.html", data)
}
-1
View File
@@ -206,7 +206,6 @@ func registerRoutes(r *gin.Engine) {
})
})
r.GET("/application/", web.Application)
r.GET("/home-road/", web.HomeRoad)
r.GET("/detail/:slug/", web.Detail)
-37
View File
@@ -1,37 +0,0 @@
package applistser
import (
"fmt"
"videoweb/app/service/upstream"
"videoweb/pub/common/log"
"github.com/gin-gonic/gin"
)
const listPath = "/api/app/applist/list"
// FetchList 拉取应用分类列表。categoryId=0 表示默认。
func FetchList(c *gin.Context, categoryID int64) (*AppListResp, error) {
path := fmt.Sprintf("%s?categoryId=%d", listPath, categoryID)
var env APIEnvelope[AppListResp]
if err := upstream.GetPublicJSON(c, path, &env); err != nil {
return nil, err
}
if env.Code != 200 {
return nil, fmt.Errorf("applist code=%d msg=%s", env.Code, env.Msg)
}
return &env.Data, nil
}
// FetchListOrEmpty 失败时返回空结构,保证 SSR 可渲染。
func FetchListOrEmpty(c *gin.Context, categoryID int64) *AppListResp {
data, err := FetchList(c, categoryID)
if err != nil {
log.Error("fetch applist failed", log.E(err))
return &AppListResp{}
}
if data == nil {
return &AppListResp{}
}
return data
}
-38
View File
@@ -1,38 +0,0 @@
package applistser
// AppListResp 对应 swagger proto.AppListResp 的业务字段(忽略无关 config/advitise)。
type AppListResp struct {
Category AppCategoryInfo `json:"category"`
CategoryList []AppCategoryInfo `json:"categoryList"`
}
// AppCategoryInfo 对应 swagger proto.AppCategoryInfo
type AppCategoryInfo struct {
ID int64 `json:"id"`
Code int `json:"code"`
Title string `json:"title"`
Intro string `json:"intro"`
Sort int `json:"sort"`
AppList []AppInfoData `json:"appList"`
}
// AppInfoData 对应 swagger proto.AppInfoData
type AppInfoData struct {
ID int64 `json:"id"`
CategoryID int64 `json:"categoryId"`
Name string `json:"name"`
Intro string `json:"intro"`
Description string `json:"description"`
Logo string `json:"logo"`
URL string `json:"url"`
Sort int `json:"sort"`
AdvitiseID string `json:"advitiseId"`
Location int `json:"location"`
}
// APIEnvelope 上游统一响应壳
type APIEnvelope[T any] struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data T `json:"data"`
}
-83
View File
@@ -1,83 +0,0 @@
package applistser
import (
"fmt"
"strings"
)
// PageVM 福利应用页模板数据
type PageVM struct {
Categories []CategoryVM
}
type CategoryVM struct {
ID int64
SectionID string
Title string
Intro string
Total int
Apps []AppCardVM
IsFirst bool
}
type AppCardVM struct {
ID int64
Name string
Intro string
Logo string
URL string
}
// BuildPageVM 按接口返回的 categoryList / appList 顺序组装页面数据,不做二次排序。
func BuildPageVM(data *AppListResp) PageVM {
vm := PageVM{Categories: []CategoryVM{}}
if data == nil {
return vm
}
list := data.CategoryList
if len(list) == 0 && data.Category.ID > 0 {
list = []AppCategoryInfo{data.Category}
}
if len(list) == 0 {
return vm
}
for i, cat := range list {
cards := make([]AppCardVM, 0, len(cat.AppList))
for _, app := range cat.AppList {
name := strings.TrimSpace(app.Name)
if name == "" {
continue
}
href := strings.TrimSpace(app.URL)
if href == "" {
href = "#"
}
intro := strings.TrimSpace(app.Intro)
if intro == "" {
intro = strings.TrimSpace(app.Description)
}
cards = append(cards, AppCardVM{
ID: app.ID,
Name: name,
Intro: intro,
Logo: strings.TrimSpace(app.Logo),
URL: href,
})
}
title := strings.TrimSpace(cat.Title)
if title == "" {
title = "应用分类"
}
vm.Categories = append(vm.Categories, CategoryVM{
ID: cat.ID,
SectionID: fmt.Sprintf("app-category-%d", cat.ID),
Title: title,
Intro: strings.TrimSpace(cat.Intro),
Total: len(cards),
Apps: cards,
IsFirst: i == 0,
})
}
return vm
}
+1 -1
View File
@@ -20,7 +20,7 @@ func IsIndexablePath(raw string) bool {
}
switch path {
case "/list", "/series", "/rank", "/today-update", "/topic", "/tag", "/category",
"/download-app", "/application", "/home-road", "/detail", "/play", "/nav",
"/download-app", "/home-road", "/detail", "/play", "/nav",
"/about-us", "/aboutUs", "/help-center", "/helpCenter":
return true
default:
+2 -18
View File
@@ -8,7 +8,6 @@ import (
"strconv"
"strings"
"time"
"videoweb/app/service/applistser"
"videoweb/app/service/configser"
"videoweb/app/service/playletser"
)
@@ -410,7 +409,7 @@ func isCollectionPath(path string) bool {
return true
}
}
return path == "/application" || path == "/nav"
return path == "/nav"
}
// itemListNode 为首页及列表型页面输出当前 SSR 首屏实际展示的站内详情链接。
@@ -449,19 +448,6 @@ func itemListNode(siteURL, pageURL string, data map[string]any) ldThing {
urls = append(urls, AbsURL(siteURL, path))
}
}
// 福利应用页是一个可见的应用集合;使用页面实际渲染的链接生成通用
// Schema.org ItemList。应用链接为外站落地页,因此不宣称具备 Google
// 站内轮播资格,只帮助搜索引擎理解页面集合语义。
if categories, ok := data["categories"].([]applistser.CategoryVM); ok {
for _, category := range categories {
for _, app := range category.Apps {
appURL := structuredURL(siteURL, app.URL)
if appURL != "" {
urls = append(urls, appURL)
}
}
}
}
seen := make(map[string]struct{}, len(urls))
unique := make([]string, 0, len(urls))
@@ -587,7 +573,7 @@ func genericBreadcrumb(siteURL, pageURL string, data map[string]any) ldThing {
}
func hasVisibleBreadcrumb(path string) bool {
for _, prefix := range []string{"/list", "/series", "/rank", "/today-update", "/topic", "/tag", "/category", "/richtext", "/application"} {
for _, prefix := range []string{"/list", "/series", "/rank", "/today-update", "/topic", "/tag", "/category", "/richtext"} {
if path == prefix || strings.HasPrefix(path, prefix+"/") {
return true
}
@@ -668,8 +654,6 @@ func pageDescription(data map[string]any, cfg configser.AppConfigVM, path string
}
}
switch path {
case "/application":
return "黄果短剧福利应用中心,精选实用应用与福利入口。"
case "/download-app":
return "下载黄果短剧APP,随时随地追看热门短剧。"
case "/home-road":
+4 -5
View File
@@ -39,8 +39,6 @@ func ResolveNavigationActiveKey(activeKey, requestPath string) string {
return "todayUpdate"
case strings.HasPrefix(path, "/category/"):
return "category"
case path == "/application" || strings.HasPrefix(path, "/application/"):
return "application"
case path == "/home-road" || strings.HasPrefix(path, "/home-road/"):
return "homeRoad"
case path == "/list" || strings.HasPrefix(path, "/detail/") || strings.HasPrefix(path, "/play/") || path == "/more" || strings.HasPrefix(path, "/more/") || path == "/search" || strings.HasPrefix(path, "/search/"):
@@ -91,7 +89,6 @@ func DefaultHeaderNav() []HeaderNavItemVM {
{Name: "回家的路", Href: "/home-road/", Key: "homeRoad"},
{Name: "今日更新", Href: "/today-update/", Key: "todayUpdate"},
{Name: "下载APP", Href: "javascript:;", Key: "downloadApp", IsDownload: true},
{Name: "福利应用", Href: "/application/", Key: "application"},
}
}
@@ -117,6 +114,10 @@ func BuildHeaderNav(info *AppTranslationInfo) []HeaderNavItemVM {
SeoInfo: normalizeNavigationSEO(cat.SeoInfo),
}
href, external, download := normalizeNavURL(cat.URLValue, name)
// 福利应用页已下线,后台残留的导航项不再展示
if !external && normalizeNavPath(href) == "/application" {
continue
}
item.Href = href
item.IsExternal = external
item.IsDownload = download
@@ -270,8 +271,6 @@ func navActiveKey(href, name string, download bool) string {
return "rank"
case "/today-update":
return "todayUpdate"
case "/application":
return "application"
case "/tag":
return "tagList"
case "/topic":
+10 -1
View File
@@ -13,7 +13,6 @@ func TestResolveNavigationActiveKey(t *testing.T) {
"/topic/editor-picks/page/2": "topic",
"/rank/2/page/3": "rank",
"/category/latest-video/": "category",
"/application": "application",
"/home-road": "homeRoad",
"/detail/example-playlet": "list",
"/play/example-playlet/chapter-1": "list",
@@ -81,3 +80,13 @@ func TestNormalizeNavURLKeepsConfiguredURL(t *testing.T) {
t.Fatalf("normalizeNavURL configured download URL = (%q, %v, %v)", href, external, download)
}
}
func TestBuildHeaderNavSkipsApplication(t *testing.T) {
items := BuildHeaderNav(&AppTranslationInfo{CategoryList: []TranslationCategory{
{Name: "排行榜", URLValue: "/rank/", CategoryType: 1},
{Name: "福利应用", URLValue: "/application/", CategoryType: 1},
}})
if len(items) != 1 || items[0].Href != "/rank/" {
t.Fatalf("BuildHeaderNav = %+v, want only /rank/", items)
}
}
-545
View File
@@ -1,545 +0,0 @@
/* Application list page — Figma 1920: side padding 60, content 1800. */
.application-page-body {
--site-footer-margin-top: 0;
min-height: 100vh;
min-height: 100dvh;
display: flex;
flex-direction: column;
overflow-x: hidden;
color: #fff;
background: #0f0f0f;
}
.application-page {
width: 100%;
max-width: 1920px;
min-height: 0;
padding: 40px 60px 36px;
overflow: visible;
box-sizing: border-box;
flex: 1 0 auto;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 36px;
display: flex;
margin: 0 auto;
}
.application-breadcrumb {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
color: rgba(255, 255, 255, 0.55);
font: 400 16px/24px "PingFang SC", "Noto Sans SC", sans-serif;
}
.application-breadcrumb a {
color: inherit;
text-decoration: none;
transition: color 180ms ease;
}
.application-breadcrumb a:hover,
.application-breadcrumb a:focus-visible,
.application-breadcrumb [aria-current="page"] {
color: #ec237f;
}
.application-page-title {
width: 100%;
color: #fff;
text-align: center;
font: 600 36px/1.35 "PingFang SC", "Noto Sans SC", sans-serif;
}
.app-category-tabs {
display: flex;
flex-wrap: wrap;
gap: 18px;
width: 100%;
justify-content: center;
}
.app-category-tab {
min-width: 119px;
height: 50px;
padding: 13px 24px;
border-radius: 25px;
border: 1px solid rgba(255, 255, 255, 0.10);
background: rgba(255, 255, 255, 0.05);
color: #999;
font-size: 18px;
font-family: PingFang SC, sans-serif;
font-weight: 400;
line-height: 24px;
cursor: pointer;
white-space: nowrap;
transition: color 180ms ease, background-color 180ms ease, border-color 180ms ease, transform 180ms ease;
}
.app-category-tab--active {
background: #EC237F;
color: #fff;
border-color: #EC237F;
}
.app-category-tab:hover,
.app-category-tab:focus-visible {
color: #fff;
background: rgba(236, 35, 127, 0.18);
border-color: rgba(236, 35, 127, 0.45);
}
.app-category-tab--active:hover,
.app-category-tab--active:focus-visible {
color: #181818;
background: #ec237f;
border-color: #ec237f;
}
.app-list-section {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
}
.app-list-section__head {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
.app-list-section__title {
margin: 0;
width: 100%;
text-align: center;
color: rgba(255, 255, 255, 0.90);
font-size: 36px;
font-family: PingFang SC, sans-serif;
font-weight: 400;
word-wrap: break-word;
}
.app-list-section__subtitle {
margin: 0;
width: 100%;
text-align: center;
color: rgba(255, 255, 255, 0.55);
font-size: 18px;
font-family: PingFang SC, sans-serif;
font-weight: 400;
line-height: 24px;
word-wrap: break-word;
}
.app-list-section__subtitle--bold {
font-weight: 600;
}
.app-card-grid {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 24px 28px;
align-items: flex-start;
}
.app-card {
width: 120px;
border-radius: 18px;
flex-direction: column;
align-items: center;
gap: 8px;
display: inline-flex;
text-decoration: none;
color: inherit;
transform: translateY(0);
transition: transform 220ms ease, filter 220ms ease;
}
.app-card:hover,
.app-card:focus-visible {
transform: translateY(-5px);
filter: brightness(1.08);
}
.app-card:focus-visible {
outline: 2px solid rgba(236, 35, 127, 0.85);
outline-offset: 4px;
}
.app-card__icon-wrap {
width: 120px;
height: 120px;
position: relative;
overflow: hidden;
border-radius: 18px;
}
.app-card__icon {
width: 120px;
height: 120px;
display: block;
object-fit: cover;
transition: transform 260ms ease;
}
.app-card:hover .app-card__icon,
.app-card:focus-visible .app-card__icon {
transform: scale(1.04);
}
.app-card__title {
align-self: stretch;
text-align: center;
color: rgba(255, 255, 255, 0.90);
font-size: 16px;
font-family: PingFang SC, sans-serif;
font-weight: 500;
line-height: 22px;
word-wrap: break-word;
}
.app-card__desc {
align-self: stretch;
text-align: center;
color: rgba(255, 255, 255, 0.55);
font-size: 12px;
font-family: PingFang SC, sans-serif;
font-weight: 400;
line-height: 18px;
word-wrap: break-word;
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.app-list-section__more {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
height: 50px;
padding: 13px 24px;
border: none;
border-radius: 25px;
background: #EC237F;
color: #fff;
font-size: 18px;
font-family: PingFang SC, sans-serif;
font-weight: 400;
line-height: 24px;
cursor: pointer;
transition: color 180ms ease, background-color 180ms ease, transform 180ms ease;
}
.app-list-section__more:hover,
.app-list-section__more:focus-visible {
color: #fff;
background: #d91d70;
transform: translateY(-1px);
}
.app-list-section__more-icon {
width: 12px;
height: 12px;
flex-shrink: 0;
transition: transform 0.2s ease;
}
.app-list-section__more-icon--up {
transform: rotate(180deg);
}
.app-list-section__more[hidden] {
display: none;
}
.app-list-section__empty {
margin: 0;
width: 100%;
text-align: center;
color: rgba(255, 255, 255, 0.55);
font-size: 16px;
}
.app-list-section--collapsible:not(.app-list-section--expanded) .app-card-grid--collapsible .app-card:nth-child(n + 9) {
display: none;
}
.app-list-section--expanded .app-card-grid--collapsible .app-card:nth-child(n + 9) {
display: inline-flex;
}
/* PC — scale with 1920 canvas */
@media (min-width: 768px) {
body.application-page-body {
--app-s: min(1, 100vw / 1920px);
}
.application-page {
width: 100%;
max-width: calc(1920px * var(--app-s));
padding: calc(40px * var(--app-s)) calc(60px * var(--app-s)) calc(36px * var(--app-s));
gap: calc(36px * var(--app-s));
}
.application-breadcrumb {
gap: calc(8px * var(--app-s));
font-size: calc(16px * var(--app-s));
line-height: calc(24px * var(--app-s));
}
.application-page-title {
font-size: calc(36px * var(--app-s));
}
.app-category-tabs {
gap: calc(18px * var(--app-s));
}
.app-category-tab {
min-width: calc(119px * var(--app-s));
height: calc(50px * var(--app-s));
padding: calc(13px * var(--app-s)) calc(24px * var(--app-s));
border-radius: calc(25px * var(--app-s));
font-size: calc(18px * var(--app-s));
line-height: calc(24px * var(--app-s));
}
.app-list-section {
gap: calc(24px * var(--app-s));
}
.app-list-section__head {
gap: calc(12px * var(--app-s));
}
.app-list-section__title {
font-size: calc(36px * var(--app-s));
}
.app-list-section__subtitle {
font-size: calc(18px * var(--app-s));
line-height: calc(24px * var(--app-s));
}
.app-card-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 100%;
max-width: calc(120px * var(--app-s) * 10 + 28px * var(--app-s) * 9);
margin-inline: auto;
gap: calc(24px * var(--app-s)) calc(28px * var(--app-s));
}
.app-card {
width: calc(120px * var(--app-s));
border-radius: calc(18px * var(--app-s));
gap: calc(8px * var(--app-s));
}
.app-card__icon-wrap,
.app-card__icon {
width: calc(120px * var(--app-s));
height: calc(120px * var(--app-s));
border-radius: calc(18px * var(--app-s));
}
.app-card__title {
font-size: calc(16px * var(--app-s));
line-height: calc(22px * var(--app-s));
}
.app-card__desc {
font-size: calc(12px * var(--app-s));
line-height: calc(18px * var(--app-s));
}
.app-list-section__more {
height: calc(50px * var(--app-s));
padding: calc(13px * var(--app-s)) calc(24px * var(--app-s));
border-radius: calc(25px * var(--app-s));
font-size: calc(18px * var(--app-s));
line-height: calc(24px * var(--app-s));
gap: calc(10px * var(--app-s));
}
/* PC: 1 row = 10 cards before collapse */
.app-list-section--collapsible:not(.app-list-section--expanded) .app-card-grid--collapsible .app-card:nth-child(n + 9) {
display: inline-flex;
}
.app-list-section--collapsible:not(.app-list-section--expanded) .app-card-grid--collapsible .app-card:nth-child(n + 11) {
display: none;
}
.app-list-section--expanded .app-card-grid--collapsible .app-card:nth-child(n + 11) {
display: inline-flex;
}
}
@media (max-width: 767px) {
.application-page-body {
background: #0f0f0f;
}
.application-page {
width: 100%;
max-width: none;
gap: 24px;
padding: 16px var(--site-shell-gutter) 12px;
}
.application-breadcrumb {
gap: 6px;
font-size: 12px;
line-height: 18px;
}
.application-page-title {
font-size: 24px;
line-height: 32px;
}
.app-category-tabs {
flex-wrap: nowrap;
gap: 6px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
justify-content: flex-start;
padding-bottom: 2px;
}
.app-category-tabs::-webkit-scrollbar {
display: none;
}
.app-category-tab {
min-width: 0;
height: auto;
padding: 6px 12px;
border-radius: 25px;
font-size: 12px;
line-height: 18px;
flex-shrink: 0;
color: rgba(255, 255, 255, 0.55);
}
.app-category-tab--active {
color: #fff;
}
.app-list-section {
gap: 12px;
}
.app-list-section__title {
font-size: 18px;
line-height: 24px;
font-weight: 400;
color: #EC237F;
}
.app-list-section:has(.app-list-section__subtitle--bold) .app-list-section__title {
color: rgba(255, 255, 255, 0.90);
font-weight: 600;
}
.app-list-section__subtitle {
font-size: 14px;
line-height: 20px;
font-weight: 400;
}
.app-card-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
justify-content: stretch;
gap: 14px 10px;
}
.app-card {
width: 100%;
min-width: 0;
gap: 4px;
border-radius: 12px;
}
.app-card__icon-wrap {
width: 100%;
height: auto;
aspect-ratio: 1;
border-radius: 14px;
}
.app-card__icon {
width: 100%;
height: 100%;
}
.app-card__title {
font-size: 14px;
line-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.app-card__desc {
font-size: 12px;
line-height: 18px;
}
.app-list-section__more {
height: auto;
padding: 10px 18px;
font-size: 12px;
line-height: 18px;
gap: 6px;
}
.app-list-section__more-icon {
width: 6px;
height: 6px;
}
.app-list-section--expanded .app-card-grid--collapsible .app-card:nth-child(n + 9) {
display: flex;
}
.app-card:hover,
.app-card:focus-visible {
transform: none;
}
}
@media (prefers-reduced-motion: reduce) {
.app-category-tab,
.app-card,
.app-card__icon,
.app-list-section__more,
.app-list-section__more-icon {
transition: none;
}
}
.section-empty,
.application-empty {
width: 100%;
padding: 32px 16px;
color: rgba(255, 255, 255, 0.45);
font-size: 14px;
text-align: center;
}
-17
View File
@@ -1,17 +0,0 @@
<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_40748_78473)">
<rect x="12" y="12" width="120" height="120" rx="60" fill="white" fill-opacity="0.05"/>
<path d="M63.1914 61.9375C62.0297 61.5379 60.7822 61.4526 59.5771 61.6914C58.7293 61.8502 57.9253 62.1894 57.2197 62.6855C56.514 63.1819 55.9225 63.8249 55.4863 64.5693C54.6806 66.1078 54.5146 67.9026 55.0254 69.5625C55.5362 71.2224 56.6825 72.6133 58.2139 73.4326L60.8184 74.9326L56.5908 77.373C56.2002 77.5979 55.8954 77.9461 55.7227 78.3623C55.5499 78.7786 55.5191 79.2404 55.6357 79.6758C55.7524 80.111 56.0096 80.4954 56.3672 80.7695C56.7248 81.0436 57.1628 81.1918 57.6133 81.1914C57.972 81.1899 58.3249 81.0963 58.6367 80.9189L63.123 78.3145V95.1826H52.2139C51.2285 95.1826 50.2528 94.9882 49.3428 94.6104C48.4327 94.2324 47.6057 93.6785 46.9102 92.9805C46.2146 92.2824 45.6637 91.4534 45.2891 90.542C44.9145 89.6307 44.7239 88.6542 44.7275 87.6689V56.3057C44.7275 55.3168 44.9233 54.3375 45.3037 53.4248C45.6842 52.512 46.2419 51.6834 46.9443 50.9873C47.6467 50.2913 48.4804 49.7413 49.3965 49.3691C50.3126 48.997 51.2935 48.8103 52.2822 48.8193H63.1914V61.9375ZM91.7998 48.8184C92.7841 48.8201 93.7585 49.0168 94.667 49.3955C95.5754 49.7742 96.4007 50.3276 97.0947 51.0254C97.7887 51.7232 98.3382 52.5515 98.7119 53.4619C99.0856 54.3724 99.276 55.3479 99.2725 56.332V87.6963C99.2724 88.6804 99.0782 89.6554 98.7012 90.5645C98.3241 91.4734 97.7716 92.299 97.0752 92.9941C96.3786 93.6895 95.5515 94.2408 94.6416 94.6162C93.7318 94.9916 92.7567 95.1844 91.7725 95.1826H67.2275V78.6416L71.1953 81C71.5085 81.174 71.8605 81.2684 72.2188 81.2734C72.6692 81.2738 73.1073 81.1255 73.4648 80.8516C73.8225 80.5774 74.0797 80.1922 74.1963 79.7568C74.3129 79.3215 74.2821 78.8596 74.1094 78.4434C73.9366 78.0273 73.6316 77.6798 73.2412 77.4551L69 74.9326L71.6318 73.3643C73.156 72.5255 74.32 71.1572 74.9043 69.5186C75.19 68.7069 75.2968 67.8431 75.2168 66.9863C75.1368 66.1295 74.8725 65.2995 74.4414 64.5547C74.0045 63.8108 73.4127 63.1691 72.707 62.6729C72.0015 62.1767 71.1973 61.8374 70.3496 61.6777C69.3228 61.482 68.2653 61.5195 67.2549 61.7871V48.8184H91.7998ZM60.3408 65.7002C61.0639 65.5604 61.8138 65.6967 62.4414 66.082C62.6511 66.2034 62.8828 66.2828 63.123 66.3145V71.5508L60.2451 69.8867C59.648 69.6153 59.1813 69.1204 58.9443 68.5088C58.7074 67.8971 58.7191 67.2172 58.9775 66.6143C59.1268 66.3738 59.3254 66.1673 59.5605 66.0098C59.7956 65.8523 60.0617 65.7468 60.3408 65.7002ZM67.377 66.0664C68.0036 65.6785 68.7544 65.5421 69.4775 65.6846C69.7574 65.7286 70.0244 65.8326 70.2598 65.9902C70.4952 66.148 70.6936 66.3555 70.8408 66.5977C70.9764 66.846 71.0579 67.1212 71.0791 67.4033C71.1002 67.6853 71.0608 67.9687 70.9639 68.2344C70.713 68.9263 70.2186 69.5036 69.5732 69.8574L67.2139 71.2207V66.1338L67.377 66.0664Z" fill="white"/>
</g>
<defs>
<filter id="filter0_d_40748_78473" x="0" y="0" width="144" height="144" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="6"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/>
<feBlend mode="multiply" in2="BackgroundImageFix" result="effect1_dropShadow_40748_78473"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_40748_78473" result="shape"/>
</filter>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.4364 10.3782C4.35325 10.4255 4.25932 10.4505 4.16367 10.4509C4.04349 10.451 3.92662 10.4115 3.83124 10.3384C3.73585 10.2653 3.66728 10.1627 3.63618 10.0466C3.60509 9.93049 3.6132 9.80738 3.65927 9.69637C3.70534 9.58537 3.78678 9.49269 3.89094 9.43273L5.01822 8.78182L4.32367 8.38182C3.91529 8.16333 3.60974 7.79237 3.47353 7.34969C3.33733 6.90702 3.38148 6.42846 3.5964 6.01818C3.71272 5.81966 3.87031 5.64842 4.05851 5.51605C4.24672 5.38368 4.46115 5.29326 4.68731 5.25091C5.00866 5.18723 5.34115 5.20982 5.65094 5.31637V1.81818H2.74185C2.47816 1.81578 2.21661 1.86565 1.97229 1.9649C1.72798 2.06415 1.50575 2.21082 1.31844 2.39644C1.13113 2.58206 0.982454 2.80295 0.880993 3.04635C0.779531 3.28975 0.727297 3.55084 0.727308 3.81455V12.1782C0.726351 12.441 0.777282 12.7013 0.87718 12.9444C0.977078 13.1874 1.12398 13.4084 1.30945 13.5945C1.49493 13.7807 1.71533 13.9284 1.95801 14.0292C2.2007 14.1299 2.46089 14.1818 2.72367 14.1818H5.63276V9.68364L4.4364 10.3782Z" fill="white"/>
<path d="M4.89089 6.31999C4.81644 6.33242 4.74549 6.36058 4.68279 6.40259C4.62009 6.44461 4.56706 6.49951 4.52725 6.56363C4.45833 6.72443 4.45513 6.90584 4.51835 7.06897C4.58156 7.2321 4.70615 7.36398 4.86543 7.43636L5.6327 7.87999V6.48363C5.56862 6.4752 5.50683 6.45419 5.45088 6.42181C5.28351 6.31905 5.08372 6.28273 4.89089 6.31999ZM13.28 1.81818H6.73452V5.27636C7.00402 5.20498 7.28612 5.19504 7.55998 5.24727C7.78606 5.28985 8.00039 5.38036 8.18857 5.5127C8.37674 5.64505 8.53438 5.81617 8.65089 6.01454C8.76585 6.21316 8.83643 6.43432 8.85777 6.66281C8.87911 6.8913 8.85071 7.12171 8.77452 7.33818C8.6187 7.77516 8.30824 8.13995 7.90179 8.36363L7.19998 8.78181L8.33088 9.45454C8.43505 9.5145 8.51649 9.60718 8.56256 9.71819C8.60862 9.82919 8.61674 9.9523 8.58565 10.0684C8.55455 10.1845 8.48598 10.2871 8.39059 10.3602C8.29521 10.4333 8.17834 10.4729 8.05816 10.4727C7.96264 10.4714 7.86894 10.4464 7.78543 10.4L6.72725 9.7709V14.1818H13.2727C13.5352 14.1823 13.7952 14.131 14.0378 14.0309C14.2804 13.9308 14.5009 13.7838 14.6867 13.5984C14.8725 13.413 15.0198 13.1927 15.1204 12.9503C15.2209 12.7078 15.2727 12.4479 15.2727 12.1854V3.82181C15.2737 3.55934 15.2228 3.29926 15.1232 3.05644C15.0235 2.81363 14.8769 2.59286 14.6918 2.40675C14.5068 2.22065 14.2868 2.07287 14.0445 1.97188C13.8023 1.87088 13.5424 1.81865 13.28 1.81818Z" fill="white"/>
<path d="M7.72363 6.99636C7.7495 6.92548 7.75996 6.8499 7.75432 6.77465C7.74867 6.69941 7.72706 6.62623 7.69091 6.56C7.65165 6.4954 7.59877 6.44013 7.53597 6.39806C7.47317 6.35598 7.40195 6.3281 7.32727 6.31636C7.13444 6.27837 6.93438 6.31474 6.76727 6.41818L6.72363 6.43636V7.79273L7.35272 7.42909C7.52486 7.33474 7.65672 7.1809 7.72363 6.99636Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

-160
View File
@@ -1,160 +0,0 @@
(function () {
const DESKTOP_COLLAPSE_LIMIT = 10;
const MOBILE_COLLAPSE_LIMIT = 8;
function initApplicationPage() {
const page = document.querySelector(".application-page");
if (!page) return;
const tabsNav = page.querySelector(".app-category-tabs");
const tabs = page.querySelectorAll(".app-category-tab");
const sections = page.querySelectorAll(".app-list-section[data-total]");
if (!tabs.length || !sections.length) return;
let isProgrammaticScroll = false;
let scrollTimer = null;
function isDesktop() {
return window.matchMedia("(min-width: 768px)").matches;
}
function getCollapseLimit() {
return isDesktop() ? DESKTOP_COLLAPSE_LIMIT : MOBILE_COLLAPSE_LIMIT;
}
function getScrollOffset() {
const header = document.querySelector(".site-header");
const barHeight = (header && header.getBoundingClientRect().height) || (isDesktop() ? 72 : 56);
return barHeight + (isDesktop() ? 24 : 12);
}
function getSectionAnchor(section) {
return section.querySelector(".app-list-section__head") || section;
}
function setActiveTab(activeTab) {
tabs.forEach((tab) => {
const isActive = tab === activeTab;
tab.classList.toggle("app-category-tab--active", isActive);
tab.setAttribute("aria-selected", isActive ? "true" : "false");
});
}
function updateActionButton(button, expanded, limit) {
const label = button.querySelector(".app-list-section__more-label");
const icon = button.querySelector(".app-list-section__more-icon");
const total = Number(button.dataset.total) || 0;
const hiddenCount = Math.max(total - limit, 0);
if (label) {
label.textContent = expanded ? "收起" : `显示全部${hiddenCount}个站点`;
}
if (icon) {
icon.classList.toggle("app-list-section__more-icon--up", expanded);
}
button.setAttribute("aria-expanded", expanded ? "true" : "false");
}
function updateCollapseSections() {
const limit = getCollapseLimit();
page.querySelectorAll(".app-list-section[data-total]").forEach((section) => {
const total = Number(section.dataset.total) || 0;
const button = section.querySelector(".app-list-section__more");
const needsCollapse = total > limit;
section.classList.toggle("app-list-section--collapsible", needsCollapse);
if (!needsCollapse) {
section.classList.remove("app-list-section--expanded");
}
if (button) {
button.hidden = !needsCollapse;
if (needsCollapse) {
updateActionButton(button, section.classList.contains("app-list-section--expanded"), limit);
}
}
});
}
function scrollTabIntoView(tab) {
if (!tabsNav || !tab) return;
const navRect = tabsNav.getBoundingClientRect();
const tabRect = tab.getBoundingClientRect();
const nextLeft = tabsNav.scrollLeft + (tabRect.left - navRect.left) - (navRect.width - tabRect.width) / 2;
tabsNav.scrollTo({ left: Math.max(0, nextLeft), behavior: "smooth" });
}
function scrollToSection(section) {
if (!section) return;
const anchor = getSectionAnchor(section);
const top = anchor.getBoundingClientRect().top + window.scrollY - getScrollOffset();
isProgrammaticScroll = true;
clearTimeout(scrollTimer);
window.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
scrollTimer = window.setTimeout(() => {
isProgrammaticScroll = false;
}, 800);
}
tabs.forEach((tab, index) => {
if (!tab.hasAttribute("aria-selected")) {
tab.setAttribute("aria-selected", index === 0 ? "true" : "false");
}
tab.addEventListener("click", () => {
const targetId = tab.dataset.target;
if (!targetId) return;
setActiveTab(tab);
scrollTabIntoView(tab);
scrollToSection(document.getElementById(targetId));
});
});
page.querySelectorAll(".app-list-section__more").forEach((button) => {
button.addEventListener("click", () => {
const section = button.closest(".app-list-section");
if (!section || button.hidden) return;
const expanded = section.classList.toggle("app-list-section--expanded");
updateActionButton(button, expanded, getCollapseLimit());
});
});
updateCollapseSections();
window.addEventListener("resize", updateCollapseSections);
if (!("IntersectionObserver" in window)) return;
const observer = new IntersectionObserver(
(entries) => {
if (isProgrammaticScroll) return;
const visible = entries
.filter((entry) => entry.isIntersecting)
.sort((a, b) => b.intersectionRatio - a.intersectionRatio);
if (!visible.length) return;
const activeTab = page.querySelector(`.app-category-tab[data-target="${visible[0].target.id}"]`);
if (activeTab) {
setActiveTab(activeTab);
}
},
{
rootMargin: `-${getScrollOffset()}px 0px -55% 0px`,
threshold: [0, 0.25, 0.5, 0.75, 1],
}
);
sections.forEach((section) => observer.observe(section));
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initApplicationPage);
} else {
initApplicationPage();
}
})();
-1
View File
@@ -142,7 +142,6 @@
<a class="{{if eq .resolvedNavActive "topic"}}is-active{{end}}" href="/topic/"{{if eq .resolvedNavActive "topic"}} aria-current="page"{{end}}>专题</a>
<a class="{{if eq .resolvedNavActive "rank"}}is-active{{end}}" href="/rank/"{{if eq .resolvedNavActive "rank"}} aria-current="page"{{end}}>排行榜</a>
<a class="{{if eq .resolvedNavActive "homeRoad"}}is-active{{end}}" href="/home-road/"{{if eq .resolvedNavActive "homeRoad"}} aria-current="page"{{end}}>回家的路</a>
<a class="{{if eq .resolvedNavActive "application"}}is-active{{end}}" href="/application/"{{if eq .resolvedNavActive "application"}} aria-current="page"{{end}}>福利应用</a>
</nav>
<div class="home-mobile-menu-contact">
{{if .appConfig.GmailAddr}}<div>E-mail:<a href="mailto:{{.appConfig.GmailAddr}}">{{.appConfig.GmailAddr}}</a></div>{{end}}
-8
View File
@@ -125,14 +125,6 @@
{{else}}
<span class="about-contact-item"><img class="about-contact-icon" src="/static/images/au_app.svg" alt="" /><span class="about-contact-label">APP</span></span>
{{end}}
{{if .appConfig.PotaoGroup}}
<a class="about-contact-item" href="{{.appConfig.PotaoGroup}}"{{if hasPrefix .appConfig.PotaoGroup "http"}} target="_blank" rel="sponsored nofollow noopener noreferrer"{{end}}>
<img class="about-contact-icon" src="/static/images/au_flyy.svg" alt="" />
<span class="about-contact-label">福利应用</span>
</a>
{{else}}
<span class="about-contact-item"><img class="about-contact-icon" src="/static/images/au_flyy.svg" alt="" /><span class="about-contact-label">福利应用</span></span>
{{end}}
</section>
</div>
</main>
-131
View File
@@ -1,131 +0,0 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{{template "seoCommon" .}}
<title>
{{if .seoInfo.Title}}{{.seoInfo.Title}}{{else if .title}}{{.title}} - 黄果短剧{{else}}福利应用 - 黄果短剧{{end}}
</title>
<meta
name="description"
content="{{if .seoInfo.Description}}{{.seoInfo.Description}}{{else}}黄果短剧福利应用中心,精选实用应用与福利入口,发现更多优质内容与服务 - 黄果短剧{{end}}"
/>
<meta name="keywords" content="{{if .seoInfo.Keywords}}{{joinStrings .seoInfo.Keywords ","}}{{else}}福利应用,应用推荐,黄果短剧,实用工具{{end}}" />
<meta property="og:type" content="website" />
<meta
property="og:title"
content="{{if .seoInfo.Title}}{{.seoInfo.Title}}{{else if .title}}{{.title}} - 黄果短剧{{else}}福利应用 - 黄果短剧{{end}}"
/>
<meta
property="og:description"
content="{{if .seoInfo.Description}}{{.seoInfo.Description}}{{else}}黄果短剧福利应用中心,精选实用应用与福利入口。{{end}}"
/>
{{if .jsonLD}}
<script type="application/ld+json">
{{.jsonLD}}
</script>
{{end}}
<link rel="stylesheet" href="/static/css/application.css?v=9" />
</head>
<body class="site-shell application-page-body has-h5-tabbar">
{{template "header" .}}
<main class="application-page">
<nav class="application-breadcrumb" aria-label="面包屑">
<a href="/">首页</a>
<span aria-hidden="true">/</span>
<span aria-current="page">福利应用</span>
</nav>
<h1 class="application-page-title">福利应用</h1>
{{if .categories}}
<nav class="app-category-tabs" aria-label="应用分类">
{{range $i, $cat := .categories}}
<button
type="button"
class="app-category-tab{{if eq $i 0}} app-category-tab--active{{end}}"
data-target="{{$cat.SectionID}}"
aria-selected="{{if eq $i 0}}true{{else}}false{{end}}"
>
{{$cat.Title}}
</button>
{{end}}
</nav>
{{range $i, $cat := .categories}}
<section
class="app-list-section"
id="{{$cat.SectionID}}"
data-total="{{$cat.Total}}"
>
<div class="app-list-section__head">
<h2 class="app-list-section__title">{{$cat.Title}}</h2>
{{if $cat.Intro}}
<p
class="app-list-section__subtitle{{if $cat.IsFirst}} app-list-section__subtitle--bold{{end}}"
>
{{$cat.Intro}}
</p>
{{end}}
</div>
<div class="app-card-grid app-card-grid--collapsible">
{{range $cat.Apps}}
<a
class="app-card"
href="{{.URL}}"
target="_blank"
rel="sponsored nofollow noopener noreferrer"
aria-label="{{.Name}}"
>
<div class="app-card__icon-wrap">
{{if .Logo}}
<img
src="/static/images/placeholder.png?v=2"
class="app-card__icon lazy"
data-src="{{.Logo}}"
alt="{{.Name}}"
title="{{.Name}}"
/>
{{else}}
<img
class="app-card__icon"
src="/static/images/placeholder.png?v=2"
alt="{{.Name}}"
title="{{.Name}}"
/>
{{end}}
</div>
<div class="app-card__title">{{.Name}}</div>
{{if .Intro}}
<div class="app-card__desc">{{.Intro}}</div>
{{end}}
</a>
{{else}}
<div class="section-empty">该分类暂无应用</div>
{{end}}
</div>
<button
type="button"
class="app-list-section__more"
data-total="{{$cat.Total}}"
hidden
>
<span class="app-list-section__more-label">显示全部</span>
<img
class="app-list-section__more-icon"
src="/static/images/tringle_down.svg"
alt="显示全部应用"
aria-hidden="true"
/>
</button>
</section>
{{end}} {{else}}
<div class="application-empty">
<div class="section-empty">暂无福利应用</div>
</div>
{{end}}
</main>
{{template "footer" .}}
<script defer src="/static/js/pages/application.js?v=3"></script>
</body>
</html>
-8
View File
@@ -94,14 +94,6 @@
<span class="nav-icon-label">APP</span>
</a>
{{end}}
{{if .appConfig.PotaoGroup}}
<a class="nav-icon-item" href="{{.appConfig.PotaoGroup}}"{{if hasPrefix .appConfig.PotaoGroup "http"}} target="_blank" rel="sponsored nofollow noopener noreferrer"{{end}}>
<span class="nav-icon-circle">
<img class="nav-icon-img" src="/static/images/figma-nav/benefits.svg" width="16" height="16" alt="" />
</span>
<span class="nav-icon-label">福利应用</span>
</a>
{{end}}
</section>
<footer class="nav-footer">
-8
View File
@@ -114,14 +114,6 @@
{{else}}
<span class="about-contact-item"><img class="about-contact-icon" src="/static/images/au_app.svg" alt="" /><span class="about-contact-label">APP</span></span>
{{end}}
{{if .appConfig.PotaoGroup}}
<a class="about-contact-item" href="{{.appConfig.PotaoGroup}}"{{if hasPrefix .appConfig.PotaoGroup "http"}} target="_blank" rel="sponsored nofollow noopener noreferrer"{{end}}>
<img class="about-contact-icon" src="/static/images/au_flyy.svg" alt="" />
<span class="about-contact-label">福利应用</span>
</a>
{{else}}
<span class="about-contact-item"><img class="about-contact-icon" src="/static/images/au_flyy.svg" alt="" /><span class="about-contact-label">福利应用</span></span>
{{end}}
</section>
{{end}}
{{else}} {{template "empty" .}} {{end}}