This commit is contained in:
谢宇宁
2026-09-15 16:25:45 +07:00
parent da39ab9a2a
commit 2d63d37930
449 changed files with 25632 additions and 24085 deletions
+1
View File
@@ -0,0 +1 @@
12
+21
View File
@@ -0,0 +1,21 @@
# AGENTS.md
> 本文件用于给 Codex CLI 及兼容 AGENTS.md 的代理 在本仓库工作时提供导航。
> 项目业务说明请参考 `README.md`。
<!-- COMMIT_CONVENTION:BEGIN -->
## Commit 规范
**格式**:`[来源] <type>(<scope>): <中文描述>`
**来源**(必填):
- `[Ai]` — AI 代理(Claude / Codex / Cursor)提交,**必须用**
- `[Human]` — 人工
- `[Migrate]` — 迁移
- `[Lib-Upgrade]` — 框架/依赖升级
**type**:`feat` / `fix` / `perf` / `style` / `docs` / `test` / `refactor` / `build` / `ci` / `chore` / `revert`
**示例**:`[Ai] feat(page): 新增活动页 V2`
<!-- COMMIT_CONVENTION:END -->
+21
View File
@@ -0,0 +1,21 @@
# CLAUDE.md
> 本文件用于给 Claude Code(claude.ai/code) 在本仓库工作时提供导航。
> 项目业务说明请参考 `README.md`。
<!-- COMMIT_CONVENTION:BEGIN -->
## Commit 规范
**格式**:`[来源] <type>(<scope>): <中文描述>`
**来源**(必填):
- `[Ai]` — AI 代理(Claude / Codex / Cursor)提交,**必须用**
- `[Human]` — 人工
- `[Migrate]` — 迁移
- `[Lib-Upgrade]` — 框架/依赖升级
**type**:`feat` / `fix` / `perf` / `style` / `docs` / `test` / `refactor` / `build` / `ci` / `chore` / `revert`
**示例**:`[Ai] feat(page): 新增活动页 V2`
<!-- COMMIT_CONVENTION:END -->
+5 -1
View File
@@ -1 +1,5 @@
# node 版本使用 12.18.1
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).
+76
View File
@@ -0,0 +1,76 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"]
};
-12
View File
@@ -1,12 +0,0 @@
# sh 执行打包到正式服上
npm run build
zip -q -r dist.zip dist
scp ./dist.zip server@116.212.120.2:/home/server/91porn/ldy/pro
ssh server@116.212.120.2 "/home/server/91porn/ldy/pro/dist.sh"
if [ $? -eq 0 ];then
echo “更新成功!“
else
echo "更新失败!"
fi
rm dist.zip
+32
View File
@@ -0,0 +1,32 @@
import fs from 'fs/promises';
import path from 'path';
import sharp from 'sharp';
const imgDir = path.join(process.cwd(), 'src/assets/image'); // 图片根目录
const imgTypes = ['.png', '.jpg', '.jpeg', '.gif']; // 支持的图片类型
async function convertImagesToWebp(dir) {
try {
const files = await fs.readdir(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const extname = path.extname(filePath);
const itemInfo = await fs.stat(filePath);
if (itemInfo.isFile() && imgTypes.includes(extname)) {
const outputFilePath = path.join(dir, `${path.basename(file, extname)}.webp`);
await sharp(filePath)
.webp({ quality: 80 }) // 调整质量
.toFile(outputFilePath);
console.log(`Converted: ${filePath} to ${outputFilePath}`);
} else if (itemInfo.isDirectory()) {
await convertImagesToWebp(filePath); // 递归处理子目录
}
}
} catch (error) {
console.error('Error:', error);
}
}
convertImagesToWebp(imgDir);
+117
View File
@@ -0,0 +1,117 @@
# Commit 规范(北斗治理规范 v1)
> 团队来源:北斗 / 瑞升
> 设计文档:`docs/superpowers/specs/2026-05-14-beidou-git-governance-design.md`(myproject 仓)
> 适用范围:JHA-126-bili / JHA-117-pronhub 两个项目编号下所有前端仓库
---
## 1. 首次安装
clone 完仓库后,在仓库根执行一次:
```bash
bash scripts/install-hooks.sh
```
效果:把 `core.hooksPath` 指向仓库内 `.githooks/`,启用本地 commit-msg 校验。
紧急绕过:
```bash
git commit --no-verify
```
仅用于紧急上线,事后必须 `git commit --amend` 补全合规 prefix 后再 push。
---
## 2. Commit Subject 必含 4 个 Prefix 之一
每条 commit 的 subject(第一行)必须以下列 4 个 prefix 之一开头,**大小写敏感、方括号包裹、后接一个空格**:
| Prefix | 含义 | 是否计入 AI 占比统计 |
|---|---|---|
| `[Ai]` | AI 辅助生成 | ✅ 计入 AI 分子 |
| `[Human]` | 纯人工 | ✅ 计入人工分子 |
| `[Lib-Upgrade]` | 框架/依赖升级(复用) | ❌ 排除(不计入分母) |
| `[Migrate]` | 跨项目迁移代码 | ❌ 排除(不计入分母) |
---
## 3. 推荐写法
Prefix 后接 Conventional Commits 风格的 `type(scope): subject`:
```
[Ai] feat(player): 钻石购买确认弹窗 ModalPayDiamondPop
[Human] fix(wallet): 修正运营后台金额 currencyType Number 兜底
[Lib-Upgrade] chore(deps): 升级 web-sdk 1.0.8 → 1.1.2
[Migrate] feat(ui): 从 bili2_h5_client 迁入 AvatarWithBadge 组件
```
常用 type:`feat / fix / refactor / docs / test / chore / perf / ci`
---
## 4. 可选 trailer:Co-Authored-By
`Co-Authored-By` 仅作元数据,**不参与 hook 校验**。统一格式(不带邮箱):
```
Co-Authored-By: Claude
Co-Authored-By: Cursor
Co-Authored-By: Copilot
Co-Authored-By: Cline
```
---
## 5. 豁免列表
下列自动生成的 commit message,hook 直接放行,无需补 prefix:
- `Merge branch ...` / `Merge remote-tracking ...`(merge 自动消息)
- `Revert "..."`(revert 自动消息)
- `fixup! ...` / `squash! ...`(rebase 临时产物)
---
## 6. 紧急绕过
```bash
git commit --no-verify
```
适用场景:线上 P0 hotfix、CI 阻塞导致无法启动 hook 时。
事后补救:
```bash
git commit --amend # 补全 prefix
git push --force-with-lease # 仅在尚未被他人 pull 时使用
```
---
## 7. FAQ
**Q1:AI 生成代码我又手工大改了一遍,算 `[Ai]` 还是 `[Human]`?**
A:看主导工作量。AI 写完后超过 50% 代码由人手改,标 `[Human]`;否则 `[Ai]`。原则:"谁产出主要代码就归谁"。
**Q2:revert 一个 `[Ai]` commit 算什么?**
A:revert 自动生成的 `Revert "..."` 消息走豁免分支,无需打 prefix。如果手动写 revert 的 subject,按"撤销动作"的来源标 prefix(自己手工写就 `[Human]`)。
**Q3:cherry-pick 从其它仓库带来的 commit 算 `[Migrate]` 吗?**
A:是。跨项目迁移(cherry-pick / 复制代码 / 移植)统一标 `[Migrate]`,不计入 AI/Human 分母。
---
## 8. 关联文档
- 本仓库 `project.md`(项目元信息 + 风险点 + 交接说明)
- myproject 仓库 `docs/superpowers/specs/2026-05-14-beidou-git-governance-design.md`(设计 spec)
- 北斗治理规范 v1(公司原始文档)
@@ -0,0 +1,519 @@
# 黄果短剧落地页(电脑版 5 变体)实施计划
> **For agentic workers:** 用 superpowers:executing-plans 或 subagent-driven-development 按 Task 执行。步骤用 `- [ ]` 勾选。
>
> **用户规则覆盖(最高优先级):**
> - 不强制 TDD:本计划不写"先写测试"步骤。
> - 收尾只做静态检查(`pnpm exec tsc --noEmit` / `pnpm build`),不跑单测/E2E。
> - 不自动 commit / push / 建 PR:除非用户明确说"提交"。
**Goal:** 把 repo 改造为黄果短剧落地页:1 个共用电脑模板 `PcLanding.vue` + 5 变体素材(背景大图 + 底部封面),进站 5 路随机分流 A~E,并更新 index.html 为简体黄果 SEO。
**Architecture:** Vue 3 `<script setup lang="ts">` + Vite + SCSS`zoom` 缩放(基于 1920×1080),绝对定位 + 图片叠加,`<picture>` webp+png。版面只写一次,`variants.ts` 映射每变体的 `bg`/`covers`。共用元素(logo/主文案/二维码文字烤成图,导航程式画)全变体复用。二维码复用 `DesktopQrcode`
**Tech Stack:** Vue 3 + Vite + SCSS + `qrcode.vue`Figma MCP `get_screenshot`(导出节点 PNG+ `curl` 下载;`pnpm webp`sharp q80)生成 webp。
**规格来源:** `docs/superpowers/specs/2026-05-29-huangguo-landing-design.md`
---
## 关键设计参数(Figma `yD7lloED2Okdp1FJTYvhe3`,变体 1 `73:53`5 变体共用版面)
画布 1920×1080,全部绝对坐标。
| 元素 | 位置 (x,y) | 尺寸 | 说明 |
|---|---|---|---|
| 背景大图 | 0,0 | 1920×1080 | 每变体不同,含底部深色渐变 |
| 顶部 pill 条 | 360,0 | 1200×70 | 半透明圆角,水平居中(CSS 画) |
| logo 锁定组 | 420,15 | 154×40 | 烤图(icon+黄果短剧+标语) |
| 联系方式 容器 | 1094,23 | 406×24 | 3 项 + 圆点分隔(程式画) |
| 主文案 | 204,308 | 630×381 | 烤图 |
| 二维码本体 | 204,750 | 180×180 | 白底圆角,内 150×150 动态二维码 |
| 二维码文字块 | 408,757 | 502×166 | 烤图 |
| 底部封面行 | 1184,778 | 606×152 | 每变体不同,烤成长条图 |
联系方式 3 项(相对 406×24 容器,容器位于顶部内容 (734,8)):
- 官方群组:item @x=0icon 24×24 + 文字 @x=30
- 圆点分隔 @x=124(竖排 4 点,2×2,间距 4px)
- 商务合作:item @x=156
- 圆点分隔 @x=280
- 渠道合作:item @x=312
导出节点 ID
| 变体(版本) | 背景 frame | 轮动 cover row |
|---|---|---|
| 1 (A) | `73:54` | `81:766` |
| 2 (B) | `73:112` | `81:735` |
| 3 (C) | `73:169` | `81:704` |
| 4 (D) | `73:225` | `81:673` |
| 5 (E) | `73:281` | `73:356` |
共用元素(从变体 1 导出):logo `73:76`、主文案 `73:62`、二维码文字 `73:69`、官方群组 icon `73:83`、商务合作 icon `73:93`、渠道合作 icon `73:104`
---
## File Structure
```
src/
├── pages/index.vue # 改:设备检测 + 5 路随机 A~E
├── components/landing/PcLanding.vue # 新:电脑共用模板
├── config/variants.ts # 新:变体素材映射 + 导航链接常量
├── components/desktop/qrcode.vue # 复用(必要时微调 .qr-inner 尺寸)
└── assets/image/hg/
├── common/ logo / theme / qr-text / icon-tg / icon-biz / icon-channel (.png+.webp)
└── pc/ bg1..bg5 / covers1..covers5 (.png+.webp)
index.html # 改:简体黄果 SEO
```
---
# Tasks
## Task 1:从 Figma 导出全部素材 PNG
**Files:**
- Create: `src/assets/image/hg/common/{logo,theme,qr-text,icon-tg,icon-biz,icon-channel}.png`
- Create: `src/assets/image/hg/pc/{bg1..bg5,covers1..covers5}.png`
导出方式:对每个节点调用 `mcp__figma__get_screenshot`fileKey `yD7lloED2Okdp1FJTYvhe3`),拿到 `image_url` 后用 `curl -s -o <目标路径> "<url>"` 下载。背景用默认整合渲染;其余叠加元素用 `contentsOnly: true`(透明底)。
- [ ] **Step 1.1:建目录**
```bash
mkdir -p src/assets/image/hg/common src/assets/image/hg/pc
```
- [ ] **Step 1.2:导出 5 张背景**`maxDimension: 1920`,默认模式)
- 73:54 → `src/assets/image/hg/pc/bg1.png`
- 73:112 → `bg2.png`
- 73:169 → `bg3.png`
- 73:225 → `bg4.png`
- 73:281 → `bg5.png`
- [ ] **Step 1.3:导出 5 张封面长条**`contentsOnly: true``maxDimension: 1212` ≈2×)
- 81:766 → `covers1.png`81:735 → `covers2.png`81:704 → `covers3.png`81:673 → `covers4.png`73:356 → `covers5.png`
- [ ] **Step 1.4:导出共用元素**`contentsOnly: true`
- 73:76 → `common/logo.png``maxDimension: 308`
- 73:62 → `common/theme.png``maxDimension: 1260`
- 73:69 → `common/qr-text.png``maxDimension: 1004`
- 73:83 → `common/icon-tg.png``maxDimension: 72`
- 73:93 → `common/icon-biz.png``maxDimension: 72`
- 73:104 → `common/icon-channel.png``maxDimension: 72`
- [ ] **Step 1.5:核对**
```bash
ls -la src/assets/image/hg/common src/assets/image/hg/pc
```
Expected14 个 png,皆非 0 字节。用 Read 抽看 `theme.png`/`qr-text.png`/`logo.png` 确认是透明底、无背景大图穿透;若穿透,改该节点为 `contentsOnly: true` 重导,或退化为 CSS 文字渲染(见 Task 3 备注)。
- [ ] **Step 1.6:生成 webp**
```bash
pnpm webp
```
Expected:上述 png 同目录生成同名 `.webp`
---
## Task 2:建立 `src/config/variants.ts`
**Files:**
- Create: `src/config/variants.ts`
- [ ] **Step 2.1:写入完整内容**
```ts
import bg1 from '~/assets/image/hg/pc/bg1.png'
import bg1W from '~/assets/image/hg/pc/bg1.webp'
import bg2 from '~/assets/image/hg/pc/bg2.png'
import bg2W from '~/assets/image/hg/pc/bg2.webp'
import bg3 from '~/assets/image/hg/pc/bg3.png'
import bg3W from '~/assets/image/hg/pc/bg3.webp'
import bg4 from '~/assets/image/hg/pc/bg4.png'
import bg4W from '~/assets/image/hg/pc/bg4.webp'
import bg5 from '~/assets/image/hg/pc/bg5.png'
import bg5W from '~/assets/image/hg/pc/bg5.webp'
import c1 from '~/assets/image/hg/pc/covers1.png'
import c1W from '~/assets/image/hg/pc/covers1.webp'
import c2 from '~/assets/image/hg/pc/covers2.png'
import c2W from '~/assets/image/hg/pc/covers2.webp'
import c3 from '~/assets/image/hg/pc/covers3.png'
import c3W from '~/assets/image/hg/pc/covers3.webp'
import c4 from '~/assets/image/hg/pc/covers4.png'
import c4W from '~/assets/image/hg/pc/covers4.webp'
import c5 from '~/assets/image/hg/pc/covers5.png'
import c5W from '~/assets/image/hg/pc/covers5.webp'
export interface PcVariant {
bg: string
bgW: string
covers: string
coversW: string
}
export const PC_VARIANTS: PcVariant[] = [
{ bg: bg1, bgW: bg1W, covers: c1, coversW: c1W },
{ bg: bg2, bgW: bg2W, covers: c2, coversW: c2W },
{ bg: bg3, bgW: bg3W, covers: c3, coversW: c3W },
{ bg: bg4, bgW: bg4W, covers: c4, coversW: c4W },
{ bg: bg5, bgW: bg5W, covers: c5, coversW: c5W },
]
export const VERSION_LETTERS = ['A', 'B', 'C', 'D', 'E'] as const
// 导航链接:官方群组已定,其余为占位,给到网址改这里即可
export const NAV_LINKS = {
group: 'https://t.me/huangguoshortdrama',
biz: '#TODO-business',
channel: '#TODO-channel',
}
```
---
## Task 3:建立 `src/components/landing/PcLanding.vue`
**Files:**
- Create: `src/components/landing/PcLanding.vue`
- [ ] **Step 3.1:写入完整 SFC**
```vue
<template>
<div class="hg-pc">
<!-- 背景大图变体 -->
<div class="bg">
<picture>
<source type="image/webp" :srcset="v.bgW" />
<img :src="v.bg" alt="" />
</picture>
</div>
<!-- 顶部 pill 导航条 -->
<div class="top">
<div class="logo">
<picture>
<source type="image/webp" :srcset="logoW" />
<img :src="logo" alt="黄果短剧" />
</picture>
</div>
<div class="nav">
<a class="item" :href="NAV_LINKS.group">
<picture>
<source type="image/webp" :srcset="iconTgW" />
<img :src="iconTg" alt="官方群组" />
</picture>
<span>官方群組</span>
</a>
<i class="dot" />
<a class="item" :href="NAV_LINKS.biz">
<picture>
<source type="image/webp" :srcset="iconBizW" />
<img :src="iconBiz" alt="商务合作" />
</picture>
<span>商務合作</span>
</a>
<i class="dot" />
<a class="item" :href="NAV_LINKS.channel">
<picture>
<source type="image/webp" :srcset="iconChW" />
<img :src="iconCh" alt="渠道合作" />
</picture>
<span>渠道合作</span>
</a>
</div>
</div>
<!-- 主文案 -->
<div class="theme">
<picture>
<source type="image/webp" :srcset="themeW" />
<img :src="theme" alt="每一帧都能解你的色" />
</picture>
</div>
<!-- 二维码区 -->
<div class="qr">
<div class="qr-box">
<DesktopQrcode />
</div>
<div class="qr-text">
<picture>
<source type="image/webp" :srcset="qrTextW" />
<img :src="qrText" alt="" />
</picture>
</div>
</div>
<!-- 底部封面行变体 -->
<div class="covers">
<picture>
<source type="image/webp" :srcset="v.coversW" />
<img :src="v.covers" alt="" />
</picture>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, onBeforeUnmount } from 'vue'
import DesktopQrcode from '~/components/desktop/qrcode.vue'
import { PC_VARIANTS, NAV_LINKS } from '~/config/variants'
import logo from '~/assets/image/hg/common/logo.png'
import logoW from '~/assets/image/hg/common/logo.webp'
import theme from '~/assets/image/hg/common/theme.png'
import themeW from '~/assets/image/hg/common/theme.webp'
import qrText from '~/assets/image/hg/common/qr-text.png'
import qrTextW from '~/assets/image/hg/common/qr-text.webp'
import iconTg from '~/assets/image/hg/common/icon-tg.png'
import iconTgW from '~/assets/image/hg/common/icon-tg.webp'
import iconBiz from '~/assets/image/hg/common/icon-biz.png'
import iconBizW from '~/assets/image/hg/common/icon-biz.webp'
import iconCh from '~/assets/image/hg/common/icon-channel.png'
import iconChW from '~/assets/image/hg/common/icon-channel.webp'
const props = defineProps<{ variant: number }>()
const v = computed(() => PC_VARIANTS[props.variant] ?? PC_VARIANTS[0])
function resizeBox() {
const w = window.innerWidth
const h = window.innerHeight
const ratio = w / h
const pct = ratio >= 1920 / 1080 ? (h / 1080) * 100 : (w / 1920) * 100
document.body.style.cssText = 'zoom:' + pct + '%'
}
onMounted(() => {
resizeBox()
window.addEventListener('resize', resizeBox)
})
onBeforeUnmount(() => window.removeEventListener('resize', resizeBox))
</script>
<style lang="scss" scoped>
img { -webkit-user-drag: none; }
.hg-pc {
user-select: none;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.bg {
position: absolute;
inset: 0;
z-index: 0;
img { width: 100%; height: 100%; object-fit: cover; }
}
.top {
position: absolute;
left: 360px;
top: 0;
width: 1200px;
height: 70px;
z-index: 3;
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(10px);
border-radius: 0 0 20px 20px;
.logo {
position: absolute;
left: 60px;
top: 15px;
width: 154px;
height: 40px;
img { width: 100%; height: 100%; object-fit: contain; }
}
.nav {
position: absolute;
left: 734px;
top: 23px;
height: 24px;
display: flex;
align-items: center;
gap: 32px;
.item {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
text-decoration: none;
img { width: 24px; height: 24px; display: block; }
span { color: #fff; font-size: 16px; line-height: 1; white-space: nowrap; }
}
.dot {
width: 2px;
height: 14px;
background-image: radial-gradient(rgba(255,255,255,0.6) 1px, transparent 1px);
background-size: 2px 4px;
}
}
}
.theme {
position: absolute;
left: 204px;
top: 308px;
width: 630px;
height: 381px;
z-index: 2;
pointer-events: none;
img { width: 100%; height: 100%; object-fit: contain; }
}
.qr {
position: absolute;
left: 204px;
top: 750px;
width: 706px;
height: 180px;
z-index: 2;
.qr-box {
position: absolute;
left: 0;
top: 0;
width: 180px;
height: 180px;
background: #fff;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.qr-text {
position: absolute;
left: 204px;
top: 7px;
width: 502px;
height: 166px;
img { width: 100%; height: 100%; object-fit: contain; }
}
}
.covers {
position: absolute;
left: 1184px;
top: 778px;
width: 606px;
height: 152px;
z-index: 2;
pointer-events: none;
img { width: 100%; height: 100%; object-fit: contain; }
}
}
</style>
```
> **备注(若 Task 1.5 发现 theme/qr-text/logo 透明导出失败):** 把对应 `<picture>` 换成 CSS 文字。logo 文字「黃果短劇」18px bold + 标语 12px;主文案标题约 60px bold + 副标 18px;二维码文字三行(24px / 18px semibold / 13px regular)。字体用系统 CJK 栈 `"PingFang SC","Microsoft YaHei",sans-serif`。
---
## Task 4:改造 `src/pages/index.vue` 为 5 路随机分流
**Files:**
- Modify: `src/pages/index.vue`
- [ ] **Step 4.1:替换为以下完整内容**
```vue
<script setup>
import PcLanding from '~/components/landing/PcLanding.vue'
import { computed, onBeforeMount, onBeforeUnmount, ref } from 'vue'
import { useEventTracker, getSessionTraceId } from '~/utils/useEventTracker'
import { VERSION_LETTERS } from '~/config/variants'
const isMobile = computed(() =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
)
const variantIndex = ref(0)
const version = computed(() => VERSION_LETTERS[variantIndex.value])
const { trackLandingPageView, trackLandingPageClick, generateSessionId } = useEventTracker()
const handleClick = (e) => {
const rawText = e?.target?.alt || e.target.innerText || ''
const tabKey = rawText.replace(/[^A-Za-z0-9_一-鿿]/g, '_').replace(/_{2,}/g, '_').replace(/^_+|_+$/g, '') || ''
const isDownload = tabKey.toLowerCase() === 'download'
trackLandingPageClick({
landing_page_id: `JHA-126${version.value}`,
tab_key: tabKey,
tab_name: rawText,
click_coordinates_x: e.clientX,
click_coordinates_y: e.clientY,
click_x_percent: Math.round((e.clientX / window.innerWidth) * 100),
click_y_percent: Math.round((e.clientY / window.innerHeight) * 100),
screen_width: window.innerWidth,
screen_height: window.innerHeight,
trace_id: isDownload ? getSessionTraceId() : generateSessionId(),
})
}
onBeforeMount(() => {
variantIndex.value = Math.floor(Math.random() * 5)
trackLandingPageView({ landing_page_id: `JHA-126${version.value}` })
window.addEventListener('click', handleClick)
})
onBeforeUnmount(() => {
window.removeEventListener('click', handleClick)
})
</script>
<template>
<!-- 手机版黄果变体待做暂时桌面/手机都先用 PcLanding 占位 -->
<PcLanding :variant="variantIndex" />
</template>
<style scoped></style>
```
> **手机过渡说明:** 黄果手机版未做,此处先全部走 `PcLanding`。手机 Figma 到位后新增 `MobileLanding.vue`,模板改为 `isMobile ? MobileLanding : PcLanding`。`isMobile` 已保留备用。
---
## Task 5:更新 `index.html` 为简体黄果 SEO
**Files:**
- Modify: `index.html`
- [ ] **Step 5.1:替换 `<title>` 与各 meta**
- `<title>``黄果短剧官网 - 竖屏短剧APP下载 | 黄果`
- `description``黄果短剧官网 —— 竖屏短剧新世代。强情节、快节奏、随时随地,把最上瘾的好故事装进你的每一个碎片时间。支持安卓/iOS下载,海量都市情感、甜宠恋爱、古装传奇、悬疑反转短剧,免费在线看。`
- `keywords`:用户提供整串清单(逗号分隔)
- `og:title``黄果短剧 | 竖屏短剧APP下载官方入口``og:site_name``黄果短剧``og:url``https://huangguo.com``og:description` 同 description
- `twitter:title/description/site` 同步为黄果
- `canonical``https://huangguo.com`
- 删除 bili 专用 `rating`adult / RTA)两行
- `favicon` / `og:image`:暂留现有(开放项)
---
## Task 6:静态检查 + 浏览器目检
> 不跑测试。先静态检查,再起 dev server 目检。
- [ ] **Step 6.1:类型检查** `pnpm exec tsc --noEmit` → 无错误
- [ ] **Step 6.2:构建** `pnpm build` → 成功输出 dist/
- [ ] **Step 6.3dev 目检** `pnpm dev`,开 `http://localhost:3000/`,多刷几次确认随机命中不同变体;核对:背景大图、顶部 logo+3 导航、主文案、二维码(扫码=当前页)、底部封面行位置正确;点官方群组跳 `https://t.me/huangguoshortdrama`;缩放窗口无横向滚动条。
---
## Self-Review
- ✅ Spec §2 架构 → Task 2/3/4。✅ §3 坐标 → Task 3 样式。✅ §4 烤图/程式画 → Task 1+3。✅ §5 分流埋点 → Task 4。✅ §6 导航链接常量 → Task 2。✅ §7 二维码现状 → 复用 DesktopQrcode。✅ §8 SEO → Task 5。✅ §9 压缩 → Task 1.6 + `<picture>` + vsharp。
- Placeholderbiz/channel 链接为有意占位(规格 §10 已记),非计划缺漏。
- 类型一致:`PC_VARIANTS`/`NAV_LINKS`/`VERSION_LETTERS` 在 Task 2 定义,Task 3/4 引用一致;`PcVariant` 字段 `bg/bgW/covers/coversW` 与模板用法一致。
- 风险:Figma 文字节点透明导出可能穿背景 → Task 1.5 已加核对 + Task 3 CSS 退化备注。
@@ -0,0 +1,173 @@
# 黄果短剧落地页设计规格(电脑版 5 变体)
> **用户规则覆盖(最高优先级):**
> - 不强制 TDD:不写"先写测试"步骤。
> - 收尾只做静态检查(`tsc --noEmit` / lint / `pnpm build`),不自动跑单测/E2E。
> - 不自动 commit / push / 建 PR:除非用户明确说"提交"。
**日期:** 2026-05-29
**范围:** 本规格只覆盖**电脑版 5 个变体**。手机版 Figma 用户稍后提供,届时另起规格沿用同一套架构。
---
## 1. 目标
把当前 repo(残留的"逼哩逼哩 bili"模板)改造为**黄果短剧**落地页。电脑版有 5 个变体,版面结构完全相同,仅**背景大图**与**底部 5 张封面**不同。进站随机分流到其中之一(5 路 A~E,各 20%),并复用现有埋点。
设计来源 Figma`yD7lloED2Okdp1FJTYvhe3`
- 变体 1 `73:53`、变体 2 `73:111`、变体 3 `73:168`、变体 4 `73:224`、变体 5 `73:280`
---
## 2. 架构总览
沿用现有技术栈:Vue 3 `<script setup lang="ts">` + Vite + SCSS,电脑端 `zoom` 缩放方案(基于 1920×1080)。**不引入新依赖**。
```
src/
├── pages/index.vue # 入口:设备检测 + 5 路随机分流 A~E
├── components/landing/PcLanding.vue # 电脑版共用模板(本次重点)
├── components/landing/MobileLanding.vue # 手机版共用模板(占位,后续做)
├── components/desktop/qrcode.vue # 复用现有二维码组件
├── config/variants.ts # 变体 → 素材映射表 + 导航链接常量
└── assets/image/hg/
├── common/ # 5 变体共用素材
│ ├── logo.png / .webp # 左上 logo 锁定组(图标+黄果短剧+标语)
│ ├── theme.png / .webp # 主文案大图(每一帧都能… + 副标)
│ ├── qr-text.png / .webp # 二维码旁文字块(安卓手机 / UC扫码 / 安装提示)
│ ├── icon-tg.png / .webp # 官方群组图标
│ ├── icon-biz.png / .webp # 商务合作图标
│ └── icon-channel.png / .webp # 渠道合作图标
└── pc/ # 每变体一份
├── bg1.png … bg5.png / .webp # 背景大图 1920×1080
└── covers1.png … covers5.png / .webp # 底部封面长条 606×152(静态,5 张烤成一张)
```
**核心思路:版面只写一次。** `PcLanding.vue` 接收 `variant`0~4prop,从 `variants.ts` 取该变体的 `bg``covers` 图,其余元素(导航、主文案、二维码区)5 变体完全共用。
---
## 3. 版面坐标(取自 Figma 变体 1 `73:53`5 变体共用)
画布 1920×1080,全部为绝对坐标。
| 元素 | 位置 (x,y) | 尺寸 | 说明 |
|---|---|---|---|
| 背景大图 | 0,0 | 1920×1080 | **每变体不同**,含底部深色渐变压暗(保证文字可读) |
| 顶部 pill 导航条 | 360,0 | 1200×70 | 半透明圆角条,水平居中 |
| ├ logo 锁定组 | 420,15 | 154×40 | 图标 40×40 + "黄果短剧" + 标语,烤成一张图 |
| └ 联系方式(3 项) | 1094,23 | 406×24 | 官方群组 / 商务合作 / 渠道合作,项间有圆点分隔 |
| 主文案 | 204,308 | 630×381 | 标题"每一幀都能 解你的色" + 副标,烤成一张图 |
| 二维码区 | 204,750 | 706×180 | 左二维码 + 右文字块 |
| ├ 二维码本体 | 204,750 | 180×180 | 白底圆角,内 150×150 动态二维码 |
| └ 二维码文字块 | 408,757 | 502×166 | 安卓手机 / 建议使用UC浏览器扫码 / 安装提示,烤成一张图 |
| 底部封面行 | 1184,778 | 606×152 | **每变体不同**,5 张 110×152 封面,间距 14px,烤成一张长条图 |
> 实作计画阶段会逐变体拉取背景与封面的 imageRef / 导出节点。3 个联系方式项的精确间距(item1@0 / 分隔@124 / item2@156 / 分隔@280 / item3@312,相对 406 宽容器)届时核对。
---
## 4. 烤图 vs 程式画(沿用 pc2 约定)
| 元素 | 做法 | 共用/变体 |
|---|---|---|
| 背景大图 | `<picture>` webp+png | **变体** bg1bg5 |
| 底部 5 封面 | 烤成 606×152 长条图 | **变体** covers1covers5 |
| logo 锁定组 | 烤图 | 共用 |
| 主文案 | 烤图 | 共用 |
| 二维码旁文字 | 烤图 | 共用 |
| 3 个导航项(图标+文字) | **程式画**:可点击、可埋点 | 共用 |
| 二维码本体 | 动态 `DesktopQrcode`(编码当前网址) | 共用 |
---
## 5. 路由 / 分流 / 埋点
改造 `src/pages/index.vue`
- 设备检测沿用现有 UA 正则。
- 把当前 `Math.random() < 0.5 ? "A" : "B"` 扩成 **5 路随机**`variantIndex = Math.floor(Math.random() * 5)`0~4),`version = ["A","B","C","D","E"][variantIndex]`
- 桌面 → `<PcLanding :variant="variantIndex" />`
- 埋点照旧:`trackLandingPageView({ landing_page_id: 'JHA-126' + version })`,点击埋点 `handleClick` 逻辑保留不动。
- **手机分支(过渡):** 黄果手机版尚未做。本期先让手机分支渲染一个简单的黄果占位(或暂时保留现有 mobile 组件),等手机 Figma 到位后换成 `<MobileLanding :variant="variantIndex" />`。**实作时确认**取哪种过渡(默认:简单占位)。
---
## 6. 导航链接(`config/variants.ts` 顶部常量,易替换)
```ts
export const NAV_LINKS = {
group: 'https://t.me/huangguoshortdrama', // 官方群组(已定)
biz: '#TODO-business', // 商务合作(待用户提供)
channel: '#TODO-channel', // 渠道合作(待用户提供)
}
```
- 商务合作 / 渠道合作链接**用户尚未提供**,先放占位常量,给到网址后改一行即可。
- 点击导航项跳转 `window.location.href = NAV_LINKS.xxx`,并经由现有 `handleClick`(监听 window click,按 alt/innerText 取 tab_key)上报埋点。
---
## 7. 二维码行为
维持现状:`DesktopQrcode` 编码 `window.location.href`(手机扫码 → 打开当前落地页的手机版)。
> 用户尚未决定是否改成固定 APK/下载链接。若后续要改,只需把 `qrcode.vue` 的 `URL.value` 来源换成固定值,影响面单一。
---
## 8. index.html SEO 改造(简体,黄果短剧)
| 字段 | 新值 |
|---|---|
| `lang` | 保持 `zh-CN` |
| `<title>` | 黄果短剧官网 - 竖屏短剧APP下载 \| 黄果 |
| `description` | 黄果短剧官网 —— 竖屏短剧新世代。强情节、快节奏、随时随地,把最上瘾的好故事装进你的每一个碎片时间。支持安卓/iOS下载,海量都市情感、甜宠恋爱、古装传奇、悬疑反转短剧,免费在线看。 |
| `keywords` | 用户提供的整串清单(黄果 / 黄果短剧 / 短剧 / 竖屏短剧 / 下载 / 安卓 / iOS / 各题材 / 竞品词 等,逗号分隔) |
| `og:title` | 黄果短剧 \| 竖屏短剧APP下载官方入口 |
| `og:site_name` | 黄果短剧 |
| `og:url` / `canonical` | https://huangguo.com |
| `og:description` / twitter 同 description |
| `theme-color` 等 | 保留 |
- `favicon` / `og:image`:暂保留现有,等黄果素材到位再换(**实作开放项**)。
- 移除 `rating: adult` / RTA 等 bili 专用、与黄果无关的 meta(实作时确认)。
---
## 9. 图片压缩流程(用户明确要求)
1. 从 Figma 导出 PNG:背景用 **1×(1920×1080**,不用 2×,控制体积;图标/封面按需 1×~2×。
2.`pnpm webp``convertToWebp.js`sharp `quality: 80`)批量生成 `.webp` 同名副本。
3. 模板用 `<picture><source type="image/webp" :srcset="xxxW" /><img :src="xxx" /></picture>` 优先吃 webp、png 后备。
4. build 时 `vite-plugin-vsharp` 再压一次。
5. 背景为最大体积项,重点核对压后单张体积(目标尽量 < 300KB webp,必要时降质量或尺寸)。
---
## 10. 开放项(实作前/中确认)
1. 商务合作 / 渠道合作 链接 — 用户提供后替换占位。
2. 二维码是否改固定下载链接 — 默认维持现状。
3. 手机分支过渡方案 — 默认简单占位。
4. favicon / og:image 黄果素材 — 默认暂留现有。
5. 是否删除 / 保留旧 bili 页面(pc/pc2/mobile/mobile2)与 `project.md` — 默认**先保留**,不在本期清理。
---
## 11. 不在本期范围
- 手机版 5 变体(等 Figma)。
- 删除旧 bili 页面 / 重写 project.md。
- 新增后端接口 / 埋点字段。
- 自动 commit / 部署。
---
## 12. 自检
- ✅ 5 变体共用版面 → `PcLanding.vue` 单组件 + `variants.ts` 映射。
- ✅ 仅背景+封面随变体变 → 素材分 `common/``pc/`
- ✅ 5 路随机分流 + 埋点 A~E → `index.vue` 改造。
- ✅ 图片压缩 → `pnpm webp` + `<picture>` + vsharp。
- ✅ 官方群组链接已定,其余占位易替换。
- ⚠️ 占位项(biz/channel 链接、二维码、手机过渡、favicon)已在第 10 节列明,不阻塞电脑版实作。
+66
View File
@@ -0,0 +1,66 @@
<!doctype html>
<html lang="zh-Hant" style="overflow: hidden;">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="HandheldFriendly" content="true" />
<meta http-equiv="x-dns-prefetch-control" content="on" />
<meta name="referrer" content="same-origin" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700;900&display=swap" rel="stylesheet" />
<title>黄果短剧|成人短剧APP|每日更新|海量高清</title>
<meta name="description" content="黄果短剧每日更新,海量高清成人短剧、成人影集在线观看,禁忌、诱惑、霸总、逆袭、穿越,精彩黄剧尽在黄果。" />
<meta name="keywords" content="黄果,huangguo,黄果短剧 官网,黄果落地页,黄果短剧 落地页,黄果APP下载,黄果短剧 APP下载,黄果短剧 APP,黄果 下载,黄果短剧 下载,黄果短剧 安卓版,黄果短剧 安卓下载,黄果短剧 APK,黄果短剧 苹果版,黄果短剧 iOS下载,黄果短剧 App Store,黄果 观看,黄果短剧 怎么看,黄果短剧 在哪看,黄果短剧 在线看,黄果短剧 免费看,黄果短剧 全集,黄果短剧 注册,黄果短剧 登录,黄果短剧 会员,黄果短剧 VIP,黄果短剧 客服,黄果短剧 官方,黄果短剧 是什么,黄果短剧 好看吗,黄果短剧 评价,黄果短剧 心得,黄果短剧 安全吗,黄果短剧 收费,黄果短剧 上线时间,黄果短剧 预订,黄果短剧 预约,黄果短剧 通知,短剧,竖屏短剧,直屏短剧,微短剧,迷你剧,短剧集,追剧,在线短剧,短剧平台,短剧 APP,短剧网站,在线看短剧,免费短剧,短剧推荐,热门短剧,短剧下载,逆袭爽剧,小人物逆袭,爽剧,都市情感剧,都市爱情剧,悬疑反转剧,悬疑短剧,甜宠恋爱剧,甜宠剧,古装传奇,古装爽剧,奇幻脑洞,穿越短剧,重生短剧,霸道总裁,通勤看剧,碎片时间追剧,一集十分钟 短剧,上瘾短剧,睡前看剧,短剧 上瘾,什么是短剧,什么是竖屏短剧,红果短剧,ReelShort,DramaBox,番茄短剧,抖音短剧,快手短剧,手机 看短剧,短剧 排行榜,2026 短剧推荐,台湾 短剧,繁体中文 短剧,日本 短剧,短剧 上线通知,黄果 上线时间" />
<meta name="robots" content="index, follow" />
<!-- Bing Webmaster Tools -->
<meta name="msvalidate.01" content="__BING_VERIFICATION_TOKEN__" />
<meta property="og:title" content="黄果短剧 | 竖屏短剧APP下载官方入口" />
<meta property="og:site_name" content="黄果短剧" />
<meta property="og:type" content="article" />
<meta property="og:image" content="/favicon.ico" />
<meta property="og:description" content="黄果短剧每日更新,海量高清成人短剧、成人影集在线观看,禁忌、诱惑、霸总、逆袭、穿越,精彩黄剧尽在黄果。" />
<meta name="twitter:title" content="黄果短剧 | 竖屏短剧APP下载官方入口" />
<meta name="twitter:description" content="黄果短剧每日更新,海量高清成人短剧、成人影集在线观看,禁忌、诱惑、霸总、逆袭、穿越,精彩黄剧尽在黄果。" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:image" content="/favicon.ico" />
<meta name="twitter:site" content="黄果短剧" />
<meta name="theme-color" content="#000000" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="#000000" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="canonical" href="https://huangguo.com" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
<!-- LandingSDK 埋点加载(v2.0.0,与 jha-505 / bili2 同版;初始化见 src/App.vue initTracker -->
<script>
(function (i, s, o, g, r) {
i[r] =
i[r] ||
function () {
var args = Array.prototype.slice.call(arguments);
return new Promise(function (resolve, reject) {
(i[r].q = i[r].q || []).push({ args: args, resolve: resolve, reject: reject });
});
};
i[r].l = 1 * new Date();
var a = s.createElement(o);
var m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, "script", "/landing-sdk-v2.0.0.js", "tracker");
</script>
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
preset: "@vue/cli-plugin-unit-jest"
};
Executable
+7
View File
@@ -0,0 +1,7 @@
set -e
pnpm run build
zip -q -r dist.zip dist
#黄果落地页地址 https://huangguo.com
scp -P 22889 dist.zip server@34.92.204.175:/home/server/huangguo/ldy/
ssh server@34.92.204.175 -p 22889 "bash /home/server/huangguo/ldy/rsupdate.sh"
+6222 -19672
View File
File diff suppressed because it is too large Load Diff
+30 -46
View File
@@ -1,55 +1,39 @@
{
"name": "landpage",
"version": "0.1.0",
"name": "my-vue3-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"test-build": "vue-cli-service build --mode test",
"lint": "eslint --fix --ext .js,.vue src",
"test:unit": "vue-cli-service test:unit"
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview",
"webp": "node convertToWebp.js"
},
"dependencies": {
"autofit.js": "^2.0.5",
"axios": "^0.19.2",
"core-js": "^3.6.5",
"element-ui": "^2.13.2",
"lib-flexible": "^0.3.2",
"moment": "^2.26.0",
"postcss-plugin-px2rem": "^0.8.1",
"postcss-px2rem": "^0.3.0",
"qrcode": "^1.4.4",
"register-service-worker": "^1.7.1",
"swiper": "^5.4.5",
"vant": "^2.8.4",
"vue": "^2.6.11",
"vue-analytics": "^5.22.1",
"vue-awesome-swiper": "^4.1.1",
"vue-clipboard2": "^0.3.1",
"vue-lottery": "^1.0.3",
"vue-router": "^3.3.1",
"vue-touch-hotfix": "^2.0.0-beta.4",
"vuex": "^3.4.0"
"ofetch": "^1.4.1",
"ohash": "^1.1.6",
"process-nextick-args": "^2.0.1",
"qrcode.vue": "^3.6.0",
"sharp": "^0.34.2",
"swiper": "^11.2.6",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.4.1",
"@vue/cli-plugin-eslint": "^4.4.1",
"@vue/cli-plugin-unit-jest": "^4.4.1",
"@vue/cli-service": "^4.4.1",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/test-utils": "1.0.0-beta.31",
"babel-eslint": "^10.0.3",
"babel-plugin-component": "^1.1.1",
"compression-webpack-plugin": "^1.1.12",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^6.1.2",
"node-sass": "^4.14.1",
"prettier": "^1.19.1",
"sass": "~1.26.5",
"sass-loader": "^8.0.2",
"vue-cli-plugin-element": "^1.0.1",
"vue-template-compiler": "^2.6.11",
"webpack-bundle-analyzer": "^4.4.0"
"@eslint/js": "^9.22.0",
"@vitejs/plugin-vue": "^5.2.1",
"globals": "^16.0.0",
"gulp": "^5.0.1",
"gulp-debug": "^5.0.1",
"gulp-rename": "^2.1.0",
"gulp-webp": "^5.0.0",
"sass": "^1.86.0",
"typescript": "^5.8.2",
"unplugin-auto-import": "^19.1.1",
"vite": "^5.4.14",
"vite-plugin-vsharp": "^1.8.1"
},
"volta": {
"node": "24.14.1"
}
}
+4223
View File
File diff suppressed because it is too large Load Diff
-196
View File
@@ -1,196 +0,0 @@
---
项目名称: 91pron H5 客户端 # 与 DMP 或内部命名一致时请自行替换
一级部门: 北斗 # 请填写一级部门名称
二级部门: 瑞升 # 请填写二级部门名称,无则留空
DMP编码: JHA-204 # 无则留空
项目类型: H5
# 可选值:
# H5 / APP / PC / 服务 / 组件 / 工具 / AI / 中间件
开发语言: Node
# 可选值:
# GO / Java / PHP / Node
项目负责人: DN4929,DN4868 # 员工编号,多个用逗号隔开,这里的负责是这套代码的负责人
运维负责人: DN9460,DN9651,DN4792 # 负责部署、监控、K8S、发布、证书等
产品负责人: YY1145,YY1208 # 项目产品经理
项目成员: DN4929,DN4868
项目状态: 开发中
# 可选值:
# 开发中 / 维护中 / 已停止 / 已归档
项目级别:
# 可选值:
# 高 / 中 / 低
核心分支: main
代码仓库:
- https://bd-git.jsyyds.com/ruisheng/jha-204-91pron/frontend/91porn-landpage-client.git
最后审计人:
最后审计时间:
告警群:
备注:
- `package.json` 中 `name` 为 `landpage`,仓库/目录名为 `91pron-landpage-client`。
- 业务 `appId` 为 **204**(见 `src/views/land/index.vue`),埋点 `appId` 为 **JHA-204**(见 `public/index.html` 与 `src/utils/eventTracker.js`)。
- 接口路径前缀为 **`/plm`**,开发环境由 `vue.config.js` 代理;选线候选域名见各环境 `.env.*` 中的 `VUE_APP_BASE_HOSTS`JSON 数组),勿将含密钥、内网地址的未脱敏内容对外发布。
---
# 1. 项目说明
本仓库为面向 **移动端 H5 浏览器**(含 PC 落地页展示)的 **Vue 2 + Vue CLI 4** 单页应用,语言为 **JavaScript**(无 TypeScript)。UI 同时使用 **Vant 2****Element UI 2**,状态管理为 **Vuex 3**(当前 store 为空壳,业务数据主要在页面组件内维护),路由为 **Vue Router 3**,模式为 **`history`HTML5 History**(见 `src/router/index.js`)。入口为 `src/main.js`,挂载 Router、Vuex、Vant、Element、剪贴板、Swiper、Google Analytics`vue-analytics`)等。
**业务定位:** 91pron **App 下载落地页**Landing Page),单路由 `/` 对应 `src/views/land/index.vue`。根据设备类型(`userAgent`)与模板版本(`version`: `A` / `B`)切换子组件:
| 场景 | 组件 |
|------|------|
| 移动端 + 版本 A | `mobile1.vue` |
| 移动端 + 版本 B | `mobile2.vue` |
| PC 端 | `pc.vue`A/B 共用) |
| 特定 PC URL | `tips.vue` |
| 接口失败选线 | `selectLinePopup.vue` |
子组件通过 props 接收 `os``configs``switchData` 等,通过 `$emit` 向上传递 `getApkInfo``recordClick` 等事件。
**启动流程(`land/index.vue`):**
1. 解析 URL 查询参数(`dc``ch``pc` 等)并写入 sessionStorage。
2. 调用 `getTemplate``/plm/okn/ijb/nuS0EDXSczKgf3Xh`)拉取按钮/下载配置(`switchData``configs`、各平台下载链接)。
3. 上报落地页展示埋点 `landingPageView``eventTracker.js``window.tracker` / LandingSDK)。
4. 用户点击下载时:`recordClick` 上报点击并调用 `getApkInfo``handleGetApkInfo` 根据终端类型跳转 iOS/Android 下载链接。
5. 接口失败时弹出 **选线弹窗**,用户选择后切换 `axios.defaults.baseURL` 并重试。
**技术栈要点:**
- 构建:**Vue CLI 4**`vue.config.js`),生产使用 **compression-webpack-plugin** 生成 **gzip** 产物。
- 样式:**Sass/SCSS**`node-sass` + `sass-loader`),`element-variables.scss` 定制 Element 主题。
- 适配:**lib-flexible** + **postcss-plugin-px2rem**`rootValue: 37.5`,设计稿基准 375px);带 **`pcm`** 选择器前缀的样式不转 rem(PC 端)。
- 网络:**axios** 封装于 `src/utils/request.js`,默认 `baseURL: '/'`,业务码 `200` 视为成功。
- 埋点:`public/index.html` 异步加载 **`/sdk/landing-sdk-v1.1.1.js`**LandingSDK),`src/utils/eventTracker.js` 封装 `landing_page_view` / `landing_page_click` 事件及设备信息解析。
- 其他:**qrcode** 生成 PC 扫码图、**vue-clipboard2** 复制渠道参数、**moment**、**swiper**、**vue-analytics**UA-165940626-2)、**register-service-worker**PWA 配置于 `vue.config.js`)。
**Node 版本:** 仓库 `README.md` 建议使用 **12.18.1**
**常用脚本(`package.json`):**
| 命令 | 说明 |
|------|------|
| `npm run dev` | 本地开发(`vue-cli-service serve` |
| `npm run build` | 生产构建 |
| `npm run test-build` | 测试环境构建(`--mode test` |
| `npm run lint` | ESLint`src``.js` / `.vue`,带 `--fix` |
| `npm run test:unit` | Jest 单元测试 |
**开发环境代理(`vue.config.js`):**
| 路径 | 说明 |
|------|------|
| `/plm` | 业务接口代理(`target` 以文件内配置为准) |
| `/dcserv` | 代理至 `https://api.shuifeng.cc`(调试用途) |
**项目目录结构(核心):**
```
91pron-landpage-client/
├── public/
│ ├── index.html # 入口 HTML,含 LandingSDK 与 SEO meta
│ └── sdk/landing-sdk-v1.1.1.js
├── src/
│ ├── main.js # 入口:Router、Vuex、Vant、Element、Analytics 等
│ ├── App.vue
│ ├── router/
│ │ └── index.js # 单路由 History 模式
│ ├── store/
│ │ └── index.js # Vuex(当前无业务 state
│ ├── views/land/
│ │ ├── index.vue # 落地页主入口:设备判断、选线、下载逻辑
│ │ └── components/ # mobile1 / mobile2 / pc / pc2 / tips / selectLinePopup
│ ├── api/ # getApkInfo、getTemplate、getIp、getCustomerServiceUrl
│ ├── utils/ # request、eventTracker、userAgent 等
│ ├── plugins/ # flexible、element、scale_no
│ └── assets/ # 样式、各模板图片(mobile1/mobile2/pc/pc2
├── vue.config.js
├── .env.development / .env.production
├── build.sh # 正式环境打包发布脚本(示例)
├── test_build.sh # 测试环境打包发布脚本(示例)
└── project.md # 本文件
```
**接口与选线:**
- 业务接口统一走 **`/plm/okn/ijb/...`** 路径(见 `src/api/`),由网关或 devServer 反代。
- **`VUE_APP_BASE_HOSTS`**:各环境 `.env.*` 中为 **JSON 数组字符串**,供选线弹窗展示候选 API 域名;用户选择后写入 `axios.defaults.baseURL` 并重试 `getTemplate`
- 生产部署需由 **Nginx / 网关****`/plm`** 转发至实际业务后端;History 模式需配置 **单页回退**`try_files``index.html`)。
---
# 2. 基础设施与中间件
本仓库为 **纯前端工程**,不内置后端;运行时依赖:
- **业务 API**`/plm` 路径下的配置与下载上报接口;静态部署时需保证 **`/plm` 反代** 与 HTTPS 证书策略一致。
- **选线域名**`VUE_APP_BASE_HOSTS` 中的候选域名需可达,否则用户只能通过选线弹窗手动切换。
- **LandingSDK**`public/sdk/landing-sdk-v1.1.1.js`,用于埋点上报(`window.tracker` / `LandingSDK.init`)。
- **静态资源托管**`npm run build` 产物在 **`dist/`**,由 CDN 或 Web 服务器提供。
- **第三方**Google Analytics`UA-165940626-2`)、可选外网 IP 查询(`api.ipify.org``getIp` 中,当前主流程未启用)。
---
# 3. 运维部署
**构建产物:** 执行 `npm run build``npm run test-build` 后,在 **`dist/`** 生成静态资源;可能同时生成 **`.gz`**(依赖服务器是否启用 `gzip_static` 或等价能力)。
**推荐发布流程(示例):**
1. 使用约定 **Node** 版本(建议 12.18.1)安装依赖:`npm ci``npm install`
2. 确认各环境 **`.env.*`** 中 `VUE_APP_BASE_HOSTS``VUE_APP_BASE_API` 等与当前发布目标一致。
3. 执行 `npm run build``npm run test-build`
4.**`dist/`** 同步至静态服务器;确认 **History 路由回退****`/plm` 反代**。
5. 仓库内 **`build.sh`**(正式)、**`test_build.sh`**(测试)为示例流程(打包 zip → scp → 远程 `dist.sh`),**主机与路径以实际运维规范为准**,避免泄露账号与内网信息。
**环境变量说明(摘录,完整以 `.env.*` 为准):**
| 变量 | 作用 |
|------|------|
| `ENV` | 环境标识(`development` / `production` |
| `VUE_APP_BASE_API` | API 根路径前缀(生产多为 `/api` |
| `VUE_APP_APP_API` | 应用 API 前缀(开发环境 `/api` |
| `VUE_APP_WEB_API` | Web API 前缀(开发环境可为空) |
| `VUE_APP_BASE_HOSTS` | 选线候选 API 域名列表(JSON 数组字符串) |
---
# 4. 风险说明
- **强依赖网关反代**:生产若 `/plm` 代理错误,**配置拉取与下载上报将不可用**;History 模式服务器配置错误会导致 **深链 404**
- **选线失败**`getTemplate` 请求失败时弹出选线弹窗;若所有候选域名不可用,用户可能无法获取下载配置。
- **埋点依赖 SDK**`LandingSDK` 未加载完成前,`window.tracker` 使用队列缓冲;SDK 加载失败会导致埋点丢失。
- **渠道参数**:下载与剪贴板逻辑依赖 URL 参数(`dc``ch``pc``tid` 等),参数缺失或格式不符可能影响跳转与统计。
- **配置敏感信息**`.env`、选线域名、部署脚本中的主机信息 **勿提交到公开仓库**;供应链上锁定 `package-lock.json` 并定期审计依赖。
---
# 5. 历史事故(可选)
- 暂无(请运维/研发后续补充)
---
# 6. 交接说明(可选)
- 落地页主逻辑集中在 **`src/views/land/index.vue`**;新增模板时参考 `mobile1` / `mobile2` / `pc` 组件模式,并在 `index.vue` 中注册与切换。
- 子组件规范见 **`.cursor/rules/vue-component.mdc`**;样式与 px2rem 见 **`.cursor/rules/scss-styling.mdc`**。
- 接口封装在 **`src/api/`**HTTP 请求统一走 **`src/utils/request.js`**。
- 埋点上报使用 **`src/utils/eventTracker.js`** 的 `landingPageView` / `landingPageClick`,勿绕过 SDK 直接上报。
- Figma 转落地页工作流见 **`.cursor/skills/figma-to-landpage/SKILL.md`**。
- **请勿将含密钥、生产内网地址的 `.env` 或未脱敏部署脚本提交至对外可见仓库**;YAML 头部元数据若与真实组织不一致,请在内部系统中核对后修改。
Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

+362
View File
@@ -0,0 +1,362 @@
[
{
"序": 1,
"落地页名称": "废柴杂役",
"素材资料夹": "LBSR-005-1-廢材雜役",
"封面来源文件": "廢材雜役-總預告-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "廢材雜役-總預告-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d01.jpg",
"类型": "短剧",
"集数": 15,
"题材标签(示意)": [
"重生",
"武侠"
]
},
{
"序": 2,
"落地页名称": "最强显示器",
"素材资料夹": "MANI-008 最强显示器",
"封面来源文件": "MANI-008 最強顯示器 EP0-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "MANI-008 最強顯示器 EP0-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d02.jpg",
"类型": "短剧",
"集数": 10,
"题材标签(示意)": [
"网游",
"穿越"
]
},
{
"序": 3,
"落地页名称": "花田里犯的错",
"素材资料夹": "ZYB-005-2 花田里犯的错",
"封面来源文件": "ZYB-005-2 花田里犯的错 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "ZYB-005-2 花田里犯的错 EP1-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d03.jpg",
"类型": "短剧",
"集数": 10,
"题材标签(示意)": [
"奇幻",
"都市"
]
},
{
"序": 4,
"落地页名称": "岁岁莲华",
"素材资料夹": "ZYB-011-01 歲歲蓮華-平面",
"封面来源文件": "竖版有字体无LOGO版.jpg",
"是否原生3比4": false,
"横版母版": "横版有字幕无LOGO.jpg",
"落地页封面档": "assets/covers2/d04.jpg",
"类型": "短剧",
"集数": 10,
"题材标签(示意)": [
"古装",
"重生"
]
},
{
"序": 5,
"落地页名称": "压抑的主妇",
"素材资料夹": "SISR-015-压抑的主妇",
"封面来源文件": "SISR-015-壓抑的主婦-总预告-竖版封面-母版.jpg",
"是否原生3比4": false,
"横版母版": "SISR-015-壓抑的主婦-总预告-横版封面-母版.jpg",
"落地页封面档": "assets/covers2/d05.jpg",
"类型": "短剧",
"集数": 10,
"题材标签(示意)": [
"都市",
"情感"
]
},
{
"序": 6,
"落地页名称": "驱魔不成",
"素材资料夹": "LBSR-007-1-驱魔不成",
"封面来源文件": "驱魔不成-总预告-竖版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "驱魔不成-总预告-横版封面-母版.png",
"落地页封面档": "assets/covers2/d06.jpg",
"类型": "短剧",
"集数": 8,
"题材标签(示意)": [
"悬疑",
"灵异"
]
},
{
"序": 7,
"落地页名称": "拳王,别喊我妹妹",
"素材资料夹": "LBSR-008-1-拳王,别喊我妹妹",
"封面来源文件": "LBSR-008-1 拳王,别喊我妹妹 總預告-豎版封面-母版.png",
"是否原生3比4": false,
"横版母版": "LBSR-008-1 拳王,别喊我妹妹 總預告-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d07.jpg",
"类型": "短剧",
"集数": 7,
"题材标签(示意)": [
"逆转",
"拳击"
]
},
{
"序": 8,
"落地页名称": "双生道侣",
"素材资料夹": "MANI-007-1 双生道侣",
"封面来源文件": "MANI-007-1 双生道侣海報 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "MANI-007-1 双生道侣海報 EP1-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d08.jpg",
"类型": "短剧",
"集数": 9,
"题材标签(示意)": [
"修仙",
"奇幻"
]
},
{
"序": 9,
"落地页名称": "孤注一掷之沉沦妙瓦底",
"素材资料夹": "ZYB-005-3 孤注一掷之沉沦妙瓦底",
"封面来源文件": "ZYB-005-3 孤注一掷之沉沦妙瓦底 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "ZYB-005-3 孤注一掷之沉沦妙瓦底 EP1-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d09.jpg",
"类型": "短剧",
"集数": 10,
"题材标签(示意)": [
"剧情",
"悬疑"
]
},
{
"序": 10,
"落地页名称": "PRISM:魔盗女团",
"素材资料夹": "SISR-001 PRISM:魔盗女团",
"封面来源文件": "PRISM:魔盗女团-竖版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "PRISM:魔盗女团-横板封面-母版.png",
"落地页封面档": "assets/covers2/d10.jpg",
"类型": "影集",
"集数": 1,
"题材标签(示意)": [
"科幻",
"偶像"
]
},
{
"序": 11,
"落地页名称": "琼明神女录",
"素材资料夹": "ZYB-017-1 琼明神女录",
"封面来源文件": "ZYB-017-1 琼明神女录EP1-豎版封面-母版(無集數).jpg",
"是否原生3比4": false,
"横版母版": "ZYB-017-1 琼明神女录EP1-橫版封面-母版(無集數).jpg",
"落地页封面档": "assets/covers2/d11.jpg",
"类型": "影集",
"集数": 1,
"题材标签(示意)": [
"仙侠",
"武侠"
]
},
{
"序": 12,
"落地页名称": "水浒淫传",
"素材资料夹": "LBSR-004-1-水滸淫傳",
"封面来源文件": "LBSR-004 水滸淫傳 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "LBSR-004-水滸淫傳 EP1-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d12.jpg",
"类型": "影集",
"集数": 2,
"题材标签(示意)": [
"古装",
"武侠"
]
},
{
"序": 13,
"落地页名称": "欲镜",
"素材资料夹": "LBSR-001-1-慾鏡",
"封面来源文件": "慾鏡EP1直版封面3比4.png",
"是否原生3比4": true,
"横版母版": "ZYL-001 慾鏡 總預告-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d13.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"悬疑",
"都市"
]
},
{
"序": 14,
"落地页名称": "妻夜怪谈",
"素材资料夹": "LBSR-003-1-妻夜怪談",
"封面来源文件": "妻夜怪談-EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "妻夜怪談-EP1-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d14.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"悬疑",
"灵异"
]
},
{
"序": 15,
"落地页名称": "触手乐园",
"素材资料夹": "LBSR-009-觸手樂園",
"封面来源文件": "LBSR-009-1 觸手樂園 總預告-豎版封面-34.jpg",
"是否原生3比4": true,
"横版母版": "LBSR-009-1 觸手樂園 總預告-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d15.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"奇幻",
"科幻"
]
},
{
"序": 16,
"落地页名称": "末雪禁城",
"素材资料夹": "MANI-003-1-末雪禁城",
"封面来源文件": "末雪禁城-EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "末雪禁城-EP1-横版封面-母版.jpg",
"落地页封面档": "assets/covers2/d16.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"古装",
"悬疑"
]
},
{
"序": 17,
"落地页名称": "透明冰棒",
"素材资料夹": "SISR-003 透明冰棒",
"封面来源文件": "透明冰棒 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "透明冰棒 EP1-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d17.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"都市",
"奇幻"
]
},
{
"序": 18,
"落地页名称": "快门沦陷",
"素材资料夹": "SISR-007 快门沦陷",
"封面来源文件": "SISR-007 快门沦陷 總預告-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "SISR-007 快门沦陷 總預告-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d18.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"都市",
"情感"
]
},
{
"序": 19,
"落地页名称": "修为尽失",
"素材资料夹": "SISR-009 修为尽失",
"封面来源文件": "SISR-009 修为尽失 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "SISR-009 修为尽失 EP1-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d19.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"仙侠",
"武侠"
]
},
{
"序": 20,
"落地页名称": "玉女心经",
"素材资料夹": "SISR-010 玉女心經",
"封面来源文件": "SISR-010 玉女心經 EP1-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "SISR-010 玉女心經 EP1-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d20.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"武侠",
"古装"
]
},
{
"序": 21,
"落地页名称": "谍影红颜",
"素材资料夹": "ZYB-006-3 谍影红颜",
"封面来源文件": "ZYB-006-3 谍影红颜 總預告-豎版封面-母版3比4.png",
"是否原生3比4": true,
"横版母版": "ZYB-006-3 谍影红颜 總預告-橫版封面-母版.jpg",
"落地页封面档": "assets/covers2/d21.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"剧情",
"悬疑"
]
},
{
"序": 22,
"落地页名称": "画皮局:胭脂债",
"素材资料夹": "ZYB-006-5 画皮局:胭脂债",
"封面来源文件": "豎版封面三比四.jpg",
"是否原生3比4": true,
"横版母版": "橫版封面.jpg",
"落地页封面档": "assets/covers2/d22.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"古装",
"奇幻"
]
},
{
"序": 23,
"落地页名称": "真的她",
"素材资料夹": "SISR-021 真的她",
"封面来源文件": "SISR-021 真的她 總預告-豎版封面-3*4版.png",
"是否原生3比4": true,
"横版母版": "SISR-021 真的她 總預告-橫版封面-母版.png",
"落地页封面档": "assets/covers2/d23.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"都市",
"情感"
]
},
{
"序": 24,
"落地页名称": "暧昧海滩",
"素材资料夹": "SISR-008 暧昧海滩",
"封面来源文件": "SISR-008 曖昧海灘 EP1-豎版封面3比4.png",
"是否原生3比4": true,
"横版母版": "SISR-008 曖昧海灘 EP1-橫版封面.jpg",
"落地页封面档": "assets/covers2/d24.jpg",
"类型": "短剧",
"集数": "未提供(显示 连载中)",
"题材标签(示意)": [
"都市",
"情感"
]
}
]
+26
View File
@@ -0,0 +1,26 @@
| 序 | 落地页名称 | 素材资料夹 | 封面来源文件 | 原生3:4 | 横版母版 |
|---|---|---|---|---|---|
| 1 | 废柴杂役 | LBSR-005-1-廢材雜役 | 廢材雜役-總預告-豎版封面-母版3比4.png | 是 | 廢材雜役-總預告-橫版封面-母版.png |
| 2 | 最强显示器 | MANI-008 最强显示器 | MANI-008 最強顯示器 EP0-豎版封面-母版3比4.png | 是 | MANI-008 最強顯示器 EP0-橫版封面-母版.png |
| 3 | 花田里犯的错 | ZYB-005-2 花田里犯的错 | ZYB-005-2 花田里犯的错 EP1-豎版封面-母版3比4.png | 是 | ZYB-005-2 花田里犯的错 EP1-橫版封面-母版.jpg |
| 4 | 岁岁莲华 | ZYB-011-01 歲歲蓮華-平面 | 竖版有字体无LOGO版.jpg | 否(定锚裁切) | 横版有字幕无LOGO.jpg |
| 5 | 压抑的主妇 | SISR-015-压抑的主妇 | SISR-015-壓抑的主婦-总预告-竖版封面-母版.jpg | 否(定锚裁切) | SISR-015-壓抑的主婦-总预告-横版封面-母版.jpg |
| 6 | 驱魔不成 | LBSR-007-1-驱魔不成 | 驱魔不成-总预告-竖版封面-母版3比4.png | 是 | 驱魔不成-总预告-横版封面-母版.png |
| 7 | 拳王,别喊我妹妹 | LBSR-008-1-拳王,别喊我妹妹 | LBSR-008-1 拳王,别喊我妹妹 總預告-豎版封面-母版.png | 否(定锚裁切) | LBSR-008-1 拳王,别喊我妹妹 總預告-橫版封面-母版.png |
| 8 | 双生道侣 | MANI-007-1 双生道侣 | MANI-007-1 双生道侣海報 EP1-豎版封面-母版3比4.png | 是 | MANI-007-1 双生道侣海報 EP1-橫版封面-母版.jpg |
| 9 | 孤注一掷之沉沦妙瓦底 | ZYB-005-3 孤注一掷之沉沦妙瓦底 | ZYB-005-3 孤注一掷之沉沦妙瓦底 EP1-豎版封面-母版3比4.png | 是 | ZYB-005-3 孤注一掷之沉沦妙瓦底 EP1-橫版封面-母版.jpg |
| 10 | PRISM:魔盗女团 | SISR-001 PRISM:魔盗女团 | PRISM:魔盗女团-竖版封面-母版3比4.png | 是 | PRISM:魔盗女团-横板封面-母版.png |
| 11 | 琼明神女录 | ZYB-017-1 琼明神女录 | ZYB-017-1 琼明神女录EP1-豎版封面-母版(無集數).jpg | 否(定锚裁切) | ZYB-017-1 琼明神女录EP1-橫版封面-母版(無集數).jpg |
| 12 | 水浒淫传 | LBSR-004-1-水滸淫傳 | LBSR-004 水滸淫傳 EP1-豎版封面-母版3比4.png | 是 | LBSR-004-水滸淫傳 EP1-橫版封面-母版.png |
| 13 | 欲镜 | LBSR-001-1-慾鏡 | 慾鏡EP1直版封面3比4.png | 是 | ZYL-001 慾鏡 總預告-橫版封面-母版.jpg |
| 14 | 妻夜怪谈 | LBSR-003-1-妻夜怪談 | 妻夜怪談-EP1-豎版封面-母版3比4.png | 是 | 妻夜怪談-EP1-橫版封面-母版.png |
| 15 | 触手乐园 | LBSR-009-觸手樂園 | LBSR-009-1 觸手樂園 總預告-豎版封面-34.jpg | 是 | LBSR-009-1 觸手樂園 總預告-橫版封面-母版.jpg |
| 16 | 末雪禁城 | MANI-003-1-末雪禁城 | 末雪禁城-EP1-豎版封面-母版3比4.png | 是 | 末雪禁城-EP1-横版封面-母版.jpg |
| 17 | 透明冰棒 | SISR-003 透明冰棒 | 透明冰棒 EP1-豎版封面-母版3比4.png | 是 | 透明冰棒 EP1-橫版封面-母版.jpg |
| 18 | 快门沦陷 | SISR-007 快门沦陷 | SISR-007 快门沦陷 總預告-豎版封面-母版3比4.png | 是 | SISR-007 快门沦陷 總預告-橫版封面-母版.jpg |
| 19 | 修为尽失 | SISR-009 修为尽失 | SISR-009 修为尽失 EP1-豎版封面-母版3比4.png | 是 | SISR-009 修为尽失 EP1-橫版封面-母版.jpg |
| 20 | 玉女心经 | SISR-010 玉女心經 | SISR-010 玉女心經 EP1-豎版封面-母版3比4.png | 是 | SISR-010 玉女心經 EP1-橫版封面-母版.png |
| 21 | 谍影红颜 | ZYB-006-3 谍影红颜 | ZYB-006-3 谍影红颜 總預告-豎版封面-母版3比4.png | 是 | ZYB-006-3 谍影红颜 總預告-橫版封面-母版.jpg |
| 22 | 画皮局:胭脂债 | ZYB-006-5 画皮局:胭脂债 | 豎版封面三比四.jpg | 是 | 橫版封面.jpg |
| 23 | 真的她 | SISR-021 真的她 | SISR-021 真的她 總預告-豎版封面-3*4版.png | 是 | SISR-021 真的她 總預告-橫版封面-母版.png |
| 24 | 暧昧海滩 | SISR-008 暧昧海滩 | SISR-008 曖昧海灘 EP1-豎版封面3比4.png | 是 | SISR-008 曖昧海灘 EP1-橫版封面.jpg |
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

+24
View File
@@ -0,0 +1,24 @@
# 首页主打(Hero)素材 · 前端配置说明(2026-09-12
轮播顺序(用户指定):01 琼明神女录 → 02 欲镜 → 03 触手乐园 → 04 PRISM:魔盗女团 → 05 废柴杂役。每部 5 个文件,命名 `NN-slug-用途.jpg`
| 用途 | 文件 | 尺寸 | 用在哪 |
|---|---|---|---|
| 横版母版(清晰) | `NN-slug-land.jpg` | 1920×1080 | PC hero 右侧主视觉卡 600×338object-fit: cover),母版自带金字剧名,不要再叠文字 |
| 模糊大图 | `NN-slug-land-blur.jpg` | 1920×1080,高斯模糊 26px | PC hero 全幅氛围底图;前端自行叠遮罩(见下) |
| 模糊压暗版 | `NN-slug-land-blur-dark.jpg` | 1920×1080 | 已把页底色 #0B0B0D 85% 混合 + 左/顶/底三层遮罩烘进去,与 Figma 稿完全一致;不想写遮罩时直接用这张 |
| H5 顶图 | `NN-slug-port-top.jpg` | 900 宽(约 900×1040 | H5 hero 顶部 375×433 区域(object-fit: cover; object-position: top),已裁掉海报自带剧名,文字区在其下 |
| 3:4 封面 | `NN-slug-cover.jpg` | 480×640 | 轮播缩略图 52×70 / 44×58,与作品区封面同一张 |
## 若用 `-land-blur.jpg` 自己叠遮罩(对齐 Figma
```css
.hero{position:relative;background:#0B0B0D}
.hero .bg{position:absolute;inset:0;background:url(01-qiongming-land-blur.jpg) center/cover;opacity:.85}
.hero .scrim-l{position:absolute;inset:0;background:linear-gradient(90deg,#0B0B0D 0%,rgba(11,11,13,.6) 30%,rgba(11,11,13,0) 62%)}
.hero .scrim-b{position:absolute;inset:0;background:linear-gradient(180deg,rgba(11,11,13,0) 50%,#0B0B0D 100%)}
.hero .scrim-t{position:absolute;left:0;right:0;top:0;height:24%;background:linear-gradient(180deg,#0B0B0D 0%,rgba(11,11,13,.6) 35%,rgba(11,11,13,0) 100%)}
```
切换主打时:底图交叉淡入 1s,卡片 / 文字 0.5s 上浮;缩略图选中态 2px #EC237F 描边;进度线 6s 一格。
## 来源
`~/Desktop/AI短劇系列平面/` 各剧的「橫版封面-母版」「豎版封面-母版」「3比4」;欲镜没有 9:16 豎版,H5 顶图取自 3:4 直版上 70%。
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>

After

Width:  |  Height:  |  Size: 356 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>

After

Width:  |  Height:  |  Size: 314 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-up"><line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline></svg>

After

Width:  |  Height:  |  Size: 310 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-award"><circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline></svg>

After

Width:  |  Height:  |  Size: 325 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bookmark"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path></svg>

After

Width:  |  Height:  |  Size: 287 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-calendar"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>

After

Width:  |  Height:  |  Size: 410 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>

After

Width:  |  Height:  |  Size: 328 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>

After

Width:  |  Height:  |  Size: 262 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>

After

Width:  |  Height:  |  Size: 269 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left"><polyline points="15 18 9 12 15 6"></polyline></svg>

After

Width:  |  Height:  |  Size: 270 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>

After

Width:  |  Height:  |  Size: 270 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>

After

Width:  |  Height:  |  Size: 268 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clock"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>

After

Width:  |  Height:  |  Size: 304 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-copy"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>

After

Width:  |  Height:  |  Size: 351 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-download"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>

After

Width:  |  Height:  |  Size: 370 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>

After

Width:  |  Height:  |  Size: 388 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>

After

Width:  |  Height:  |  Size: 316 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-film"><rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect><line x1="7" y1="2" x2="7" y2="22"></line><line x1="17" y1="2" x2="17" y2="22"></line><line x1="2" y1="12" x2="22" y2="12"></line><line x1="2" y1="7" x2="7" y2="7"></line><line x1="2" y1="17" x2="7" y2="17"></line><line x1="17" y1="17" x2="22" y2="17"></line><line x1="17" y1="7" x2="22" y2="7"></line></svg>

After

Width:  |  Height:  |  Size: 586 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-filter"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon></svg>

After

Width:  |  Height:  |  Size: 290 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-globe"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>

After

Width:  |  Height:  |  Size: 409 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-grid"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>

After

Width:  |  Height:  |  Size: 404 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-headphones"><path d="M3 18v-6a9 9 0 0 1 18 0v6"></path><path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path></svg>

After

Width:  |  Height:  |  Size: 395 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-heart"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>

After

Width:  |  Height:  |  Size: 371 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-help-circle"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>

After

Width:  |  Height:  |  Size: 365 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-image"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>

After

Width:  |  Height:  |  Size: 369 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-info"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>

After

Width:  |  Height:  |  Size: 347 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layers"><polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline></svg>

After

Width:  |  Height:  |  Size: 365 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-list"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>

After

Width:  |  Height:  |  Size: 482 B

Some files were not shown because too many files have changed in this diff Show More