今日新增修改:

This commit is contained in:
乘风
2026-04-28 18:39:08 +08:00
parent aec0c59b09
commit 78d39ed8a5
409 changed files with 15992 additions and 105173 deletions

View File

@@ -0,0 +1,299 @@
# -*- coding: utf-8 -*-
"""从 miniprogram 同步 wxss 到 reactH5 的 cssP1 页面 + 全局 + TabBar + 登录)。"""
import os
import shutil
BASE = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
# 写入 index wxss 后追加(对齐 scroll-view 横滑 / 触摸)
INDEX_CSS_H5_TAIL = """
/* ----- H5 增补(对齐小程序 scroll-view 与可点反馈;源 wxss 无此块) ----- */
.super-scroll {
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
}
.super-scroll-inner {
min-height: min-content;
}
.banner-card,
.contact-btn,
.featured-item,
.super-empty-btn,
.super-item-h,
.timeline-item,
.latest-expand-hint {
cursor: pointer;
-webkit-tap-highlight-color: transparent;
user-select: none;
}
.contact-btn:active,
.featured-item:active,
.banner-card:active,
.super-empty-btn:active,
.super-item-h:active {
opacity: 0.97;
}
/* ----- H5左右安全区刘海/曲面);并提高首页作用域优先级,避免被其它页面同名类覆盖 ----- */
.index-page.page {
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
box-sizing: border-box;
}
.index-page .main-content {
padding-left: 32rpx;
padding-right: 32rpx;
box-sizing: border-box;
}
.index-page .main-content .super-scroll,
.index-page .section .super-scroll,
.index-page .main-content .super-loading,
.index-page .section .super-loading {
margin-left: 0;
margin-right: 0;
}
"""
# TabBarH5 用内联 SVGTabBarIcons需固定尺寸类名
TABBAR_CSS_H5_TAIL = """
/* ----- H5 增补:普通 Tab 为矢量描边(见 TabBarIcons与 inactive #8e8e93 / active #00CED1 一致 ----- */
.tab-icon-svg {
width: 48rpx;
height: 48rpx;
display: block;
flex-shrink: 0;
}
/* ----- H5TabBar 贴合左右安全区,避免首尾图标贴直角边 ----- */
.tab-bar {
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
box-sizing: border-box;
}
"""
CHAPTERS_CSS_H5_TAIL = """
/* ----- H5目录页 scoped 兜底,避免与首页/匹配页同名类互相覆盖导致样式错乱 ----- */
.chapters-page.page {
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
box-sizing: border-box;
}
.chapters-page .chapters-content {
padding: 16rpx 24rpx;
width: 100%;
box-sizing: border-box;
}
.chapters-page .book-card-title {
font-size: 30rpx;
font-weight: 700;
color: #ffffff;
}
.chapters-page .part-title {
font-size: 27rpx;
font-weight: 600;
color: #ffffff;
}
.chapters-page .section-title {
font-size: 25rpx;
color: #ffffff;
white-space: normal;
word-break: break-word;
overflow-wrap: anywhere;
line-height: 1.35;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
flex: 1;
}
.chapters-page .tag {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
padding: 4rpx 14rpx;
min-width: 64rpx;
border-radius: 8rpx;
box-sizing: border-box;
text-align: center;
}
.chapters-page .tag-free {
background: rgba(0, 206, 209, 0.1);
color: #00CED1;
}
.chapters-page .section-item {
display: flex;
width: 100%;
box-sizing: border-box;
align-items: flex-start;
}
.chapters-page .chapters-list {
margin-top: 12rpx;
margin-left: 12rpx;
}
.chapters-page .part-item {
display: block;
width: 100%;
margin-bottom: 12rpx;
}
.chapters-page .part-item > .chapters-list {
display: block;
width: 100%;
}
.chapters-page .part-header {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
column-gap: 12rpx;
width: 100%;
box-sizing: border-box;
}
.chapters-page .part-left {
min-width: 0;
}
.chapters-page .part-right {
justify-self: end;
white-space: nowrap;
display: inline-flex;
align-items: center;
gap: 12rpx;
}
.chapters-page .section-list {
display: block;
width: 100%;
}
.chapters-page .chapter-header {
display: block;
width: 100%;
padding: 14rpx 24rpx;
font-size: 23rpx;
font-weight: 500;
color: rgba(255, 255, 255, 0.5);
border-bottom: 1rpx solid rgba(255, 255, 255, 0.04);
}
.chapters-page .section-left {
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 14rpx;
flex: 1;
min-width: 0;
}
.chapters-page .section-right {
display: flex;
align-items: center;
gap: 12rpx;
flex-shrink: 0;
margin-left: 12rpx;
padding-top: 2rpx;
}
.chapters-page .card {
background: rgba(28, 28, 30, 0.7);
border-radius: 20rpx;
border: 1rpx solid rgba(255, 255, 255, 0.04);
margin: 0 12rpx 16rpx 12rpx;
box-sizing: border-box;
}
"""
PAIRS = [
("miniprogram/app.wxss", "reactH5/src/styles/app-global.css"),
("miniprogram/pages/index/index.wxss", "reactH5/src/pages/Index/IndexPage.css"),
("miniprogram/pages/chapters/chapters.wxss", "reactH5/src/pages/Chapters/ChaptersPage.css"),
("miniprogram/pages/match/match.wxss", "reactH5/src/pages/Match/MatchPage.css"),
("miniprogram/pages/my/my.wxss", "reactH5/src/pages/My/MyPage.css"),
("miniprogram/custom-tab-bar/index.wxss", "reactH5/src/components/TabBar/TabBar.css"),
("miniprogram/components/login-modal/login-modal.wxss", "reactH5/src/components/LoginModal/LoginModal.css"),
("miniprogram/pages/dev-login/dev-login.wxss", "reactH5/src/pages/DevLogin/DevLoginPage.css"),
]
def copy_tree_merge(src_dir: str, dst_dir: str) -> None:
if not os.path.isdir(src_dir):
print("SKIP dir missing:", src_dir)
return
os.makedirs(dst_dir, exist_ok=True)
for root, _, files in os.walk(src_dir):
rel = os.path.relpath(root, src_dir)
out_root = os.path.join(dst_dir, rel) if rel != "." else dst_dir
os.makedirs(out_root, exist_ok=True)
for name in files:
shutil.copy2(os.path.join(root, name), os.path.join(out_root, name))
print("ASSETS merged", src_dir, "->", dst_dir)
def main():
# 静态资源SVG/图片等与小程序共用一份
copy_tree_merge(
os.path.join(BASE, "miniprogram", "assets"),
os.path.join(BASE, "reactH5", "public", "assets"),
)
st_src = os.path.join(BASE, "miniprogram", "static")
st_dst = os.path.join(BASE, "reactH5", "public", "static")
if os.path.isdir(st_src):
os.makedirs(st_dst, exist_ok=True)
for fn in os.listdir(st_src):
shutil.copy2(os.path.join(st_src, fn), os.path.join(st_dst, fn))
print("STATIC", st_src, "->", st_dst)
# iconfont同步 wxss + 注入与小程序一致的 CDNapp.js loadIconFont
ic_wxss = os.path.join(BASE, "miniprogram", "static", "iconfont.wxss")
ic_css = os.path.join(BASE, "reactH5", "src", "styles", "iconfont.css")
if os.path.isfile(ic_wxss):
with open(ic_wxss, "r", encoding="utf-8", errors="replace") as f:
ic_text = f.read()
CDN_MARK = "at.alicdn.com"
if CDN_MARK not in ic_text:
old = " src: url('/static/iconfont.woff2') format('woff2'),"
new = (
" src: url('https://at.alicdn.com/t/c/font_5142223_1sq6pv9vvbt.woff2') format('woff2'),\n"
" url('/static/iconfont.woff2') format('woff2'),"
)
if old in ic_text:
ic_text = ic_text.replace(old, new, 1)
icon_cmp = os.path.join(BASE, "miniprogram", "components", "icon", "icon.wxss")
if os.path.isfile(icon_cmp):
with open(icon_cmp, "r", encoding="utf-8", errors="replace") as f:
cmp_txt = f.read().strip()
ic_text += "\n\n/* H5 appended: miniprogram/components/icon/icon.wxss */\n"
ic_text += cmp_txt + "\n"
ic_header = "/* Synced from miniprogram/static/iconfont.wxss + H5 CDN + icon/component */\n"
os.makedirs(os.path.dirname(ic_css), exist_ok=True)
with open(ic_css, "w", encoding="utf-8", newline="\n") as f:
f.write(ic_header + ic_text)
print("OK iconfont.css")
for src_rel, dst_rel in PAIRS:
src = os.path.join(BASE, src_rel.replace("/", os.sep))
dst = os.path.join(BASE, dst_rel.replace("/", os.sep))
if not os.path.isfile(src):
print("SKIP missing:", src_rel)
continue
with open(src, "r", encoding="utf-8", errors="replace") as f:
text = f.read()
# app.wxss 中两处 page { 均映射为 H5 根选择器
if "app.wxss" in src_rel:
text = text.replace("page {", ":root, html, body, #root {")
header = "/* Auto-synced from miniprogram → reactH5; 源: %s */\n" % src_rel
if "pages/index/index.wxss" in src_rel:
text += INDEX_CSS_H5_TAIL
if "pages/chapters/chapters.wxss" in src_rel:
text += CHAPTERS_CSS_H5_TAIL
if "custom-tab-bar/index.wxss" in src_rel:
text += TABBAR_CSS_H5_TAIL
os.makedirs(os.path.dirname(dst), exist_ok=True)
with open(dst, "w", encoding="utf-8", newline="\n") as f:
f.write(header + text)
print("OK", dst_rel, len(text), "chars")
if __name__ == "__main__":
main()