diff --git a/app/api/web/application.go b/app/api/web/application.go deleted file mode 100644 index c5203ac..0000000 --- a/app/api/web/application.go +++ /dev/null @@ -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) -} diff --git a/app/router/gin.go b/app/router/gin.go index bf4055c..942aa6b 100644 --- a/app/router/gin.go +++ b/app/router/gin.go @@ -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) diff --git a/app/service/applistser/list.go b/app/service/applistser/list.go deleted file mode 100644 index 213a19c..0000000 --- a/app/service/applistser/list.go +++ /dev/null @@ -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 -} diff --git a/app/service/applistser/types.go b/app/service/applistser/types.go deleted file mode 100644 index 96f89d4..0000000 --- a/app/service/applistser/types.go +++ /dev/null @@ -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"` -} diff --git a/app/service/applistser/view.go b/app/service/applistser/view.go deleted file mode 100644 index eede6c7..0000000 --- a/app/service/applistser/view.go +++ /dev/null @@ -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 -} diff --git a/app/service/seoser/indexable.go b/app/service/seoser/indexable.go index c6404dd..218ec87 100644 --- a/app/service/seoser/indexable.go +++ b/app/service/seoser/indexable.go @@ -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: diff --git a/app/service/seoser/jsonld.go b/app/service/seoser/jsonld.go index 7dd706b..9c3bacf 100644 --- a/app/service/seoser/jsonld.go +++ b/app/service/seoser/jsonld.go @@ -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,20 +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)) for _, itemURL := range urls { @@ -587,7 +572,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 +653,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": diff --git a/app/service/translationser/view.go b/app/service/translationser/view.go index 644db5f..78638e3 100644 --- a/app/service/translationser/view.go +++ b/app/service/translationser/view.go @@ -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": diff --git a/app/service/translationser/view_test.go b/app/service/translationser/view_test.go index f4fc21e..4be29e2 100644 --- a/app/service/translationser/view_test.go +++ b/app/service/translationser/view_test.go @@ -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", diff --git a/app/static/css/application.css b/app/static/css/application.css deleted file mode 100644 index 77f3948..0000000 --- a/app/static/css/application.css +++ /dev/null @@ -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; -} diff --git a/app/static/images/au_flyy.svg b/app/static/images/au_flyy.svg deleted file mode 100644 index 6e75a99..0000000 --- a/app/static/images/au_flyy.svg +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/app/static/images/figma-dialogs/download-logo-mobile.svg b/app/static/images/figma-dialogs/download-logo-mobile.svg index 01050c0..731dbcb 100644 --- a/app/static/images/figma-dialogs/download-logo-mobile.svg +++ b/app/static/images/figma-dialogs/download-logo-mobile.svg @@ -1 +1 @@ - + diff --git a/app/static/images/figma-dialogs/download-logo-pc.svg b/app/static/images/figma-dialogs/download-logo-pc.svg index b695f62..65a2859 100644 --- a/app/static/images/figma-dialogs/download-logo-pc.svg +++ b/app/static/images/figma-dialogs/download-logo-pc.svg @@ -1 +1 @@ - + diff --git a/app/static/images/figma-home/footer-logo-desktop.png b/app/static/images/figma-home/footer-logo-desktop.png index 5ae6f95..cb4aff0 100644 Binary files a/app/static/images/figma-home/footer-logo-desktop.png and b/app/static/images/figma-home/footer-logo-desktop.png differ diff --git a/app/static/images/figma-nav/benefits.svg b/app/static/images/figma-nav/benefits.svg deleted file mode 100644 index df630dd..0000000 --- a/app/static/images/figma-nav/benefits.svg +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/app/static/images/logo.png b/app/static/images/logo.png index 47e5c3c..fd6533a 100644 Binary files a/app/static/images/logo.png and b/app/static/images/logo.png differ diff --git a/app/static/js/pages/application.js b/app/static/js/pages/application.js deleted file mode 100644 index af6bdc3..0000000 --- a/app/static/js/pages/application.js +++ /dev/null @@ -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(); - } -})(); diff --git a/app/templates/base/downloadAppDialog.html b/app/templates/base/downloadAppDialog.html index 812bddd..256daef 100644 --- a/app/templates/base/downloadAppDialog.html +++ b/app/templates/base/downloadAppDialog.html @@ -8,8 +8,8 @@