'cbook'
This commit is contained in:
@@ -6,5 +6,15 @@ module.exports = {
|
||||
'process.env.TARO_API_API': JSON.stringify("/api")
|
||||
},
|
||||
mini: {},
|
||||
h5: {}
|
||||
h5: {
|
||||
devServer: {
|
||||
hot: true,
|
||||
client: {
|
||||
overlay: {
|
||||
errors: true,
|
||||
warnings: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from "path";
|
||||
const WebpackObfuscator = require("webpack-obfuscator");
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
|
||||
const config = {
|
||||
projectName: "cityh5",
|
||||
@@ -15,25 +16,28 @@ const config = {
|
||||
compiler: "webpack5",
|
||||
|
||||
cache: {
|
||||
enable: true, // ✅ 开启缓存,加快构建
|
||||
enable: true,
|
||||
type: "filesystem",
|
||||
},
|
||||
|
||||
h5: {
|
||||
webpackChain(chain) {
|
||||
// ✅ 避免 undefined.js,统一使用标准占位符
|
||||
chain.output.filename("static/js/[name].[contenthash:8].js");
|
||||
chain.output.chunkFilename("static/js/[name].[contenthash:8].js");
|
||||
if (isDev) {
|
||||
chain.output.filename("static/js/[name].js");
|
||||
chain.output.chunkFilename("static/js/[name].js");
|
||||
chain.devtool("eval-cheap-module-source-map");
|
||||
} else {
|
||||
chain.output.filename("static/js/[name].[contenthash:8].js");
|
||||
chain.output.chunkFilename("static/js/[name].[contenthash:8].js");
|
||||
|
||||
chain.plugin("MiniCssExtractPlugin").use(require("mini-css-extract-plugin"), [
|
||||
{
|
||||
filename: "static/css/[name].[contenthash:8].css",
|
||||
chunkFilename: "static/css/[name].[contenthash:8].css",
|
||||
},
|
||||
]);
|
||||
chain.plugin("MiniCssExtractPlugin").use(require("mini-css-extract-plugin"), [
|
||||
{
|
||||
filename: "static/css/[name].[contenthash:8].css",
|
||||
chunkFilename: "static/css/[name].[contenthash:8].css",
|
||||
},
|
||||
]);
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
// ✅ 保留原有混淆逻辑
|
||||
const WebpackObfuscator = require("webpack-obfuscator");
|
||||
chain.plugin("obfuscator").use(WebpackObfuscator, [
|
||||
{
|
||||
rotateStringArray: true,
|
||||
@@ -53,7 +57,6 @@ const config = {
|
||||
]);
|
||||
}
|
||||
|
||||
// ✅ markdown 支持
|
||||
chain.module
|
||||
.rule("markdown")
|
||||
.test(/\.md$/)
|
||||
@@ -61,7 +64,6 @@ const config = {
|
||||
.loader("raw-loader")
|
||||
.end();
|
||||
|
||||
// ✅ ico 支持
|
||||
chain.module
|
||||
.rule("ico")
|
||||
.test(/\.ico$/)
|
||||
@@ -71,7 +73,7 @@ const config = {
|
||||
},
|
||||
|
||||
esnextModules: ["taro-ui"],
|
||||
publicPath: "/", // ✅ 部署到根目录;如果是子路径,需要改成 /xxx/
|
||||
publicPath: "/",
|
||||
staticDirectory: "static",
|
||||
|
||||
postcss: {
|
||||
@@ -94,6 +96,7 @@ const config = {
|
||||
},
|
||||
|
||||
devServer: {
|
||||
hot: true,
|
||||
proxy: {
|
||||
"/api/": {
|
||||
target: "http://localhost:8700",
|
||||
@@ -101,7 +104,7 @@ const config = {
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
allowedHosts: ["nomadro.com", "localhost", ".nomadro.com", "hackrobot.cn",".ngrok-free.app"],
|
||||
allowedHosts: ["nomadro.com", "localhost", ".nomadro.com", "hackrobot.cn", ".ngrok-free.app"],
|
||||
},
|
||||
|
||||
htmlPluginOption: {
|
||||
|
||||
72
src/app.js
72
src/app.js
@@ -1,72 +1,26 @@
|
||||
import { Component } from 'react'
|
||||
import SDK from 'sr-sdk-h5'
|
||||
|
||||
import './app.scss'
|
||||
import 'animate.css';
|
||||
import 'taro-ui/dist/style/index.scss' // 全局引入一次即可
|
||||
import 'animate.css'
|
||||
import 'taro-ui/dist/style/index.scss'
|
||||
|
||||
/**
|
||||
* 有数埋点SDK 默认配置
|
||||
* 使用方法请参考文档 https://mp.zhls.qq.com/youshu-docs/develop/sdk/Taro.html
|
||||
* 如对有数SDK埋点接入有任何疑问,请联系微信:sr_data_service
|
||||
*/
|
||||
|
||||
window.srt = new SDK({
|
||||
|
||||
/**
|
||||
* 有数 - ka‘接入测试用’ 分配的 app_id,对应的业务
|
||||
*/
|
||||
token: 'bi72fccc7184ef45f9',
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
|
||||
/**
|
||||
* 传入自定义的后台上报接口,若传入则token将无意义
|
||||
*/
|
||||
// serverUrl: 'aaa.baidu.com',
|
||||
|
||||
/**
|
||||
* 开启打印调试信息, 默认 false
|
||||
*/
|
||||
debug: true,
|
||||
|
||||
/**
|
||||
* 代理配置,自动代理页面浏览事件、页面离开事件、点击事件,默认 false。建议开启
|
||||
*/
|
||||
autoTrack: true,
|
||||
|
||||
/**
|
||||
* 自动开始上报,默认 true。建议开启
|
||||
*/
|
||||
autoStart: true,
|
||||
|
||||
/**
|
||||
* 上报返回的钩子函数,返回 false 则代表不通过,SDK不会清除本地记录,会继续重拾
|
||||
*/
|
||||
// onUploaded?: () => {},
|
||||
|
||||
/**
|
||||
* 跳过初始化时对 token 的必要检查
|
||||
* 满足场景:服务商转发SDK上报数据,在服务端回填appid,解决大量小程序同时接入的问题,默认false
|
||||
*/
|
||||
// skipTokenCheck: false,
|
||||
|
||||
/**
|
||||
* 小程序appid
|
||||
*/
|
||||
appid: ''
|
||||
});
|
||||
|
||||
// window.srt.setChan({chan_id: 'xxx'}) // 设置渠道,渠道信息将会被设置在props.chan对象中
|
||||
|
||||
// window.srt.setUser({user_id: 'xxx'}) // 设置用户信息,用户信息将会被设置在props.wx_user对象中
|
||||
if (isProd) {
|
||||
const SDK = require('sr-sdk-h5').default
|
||||
window.srt = new SDK({
|
||||
token: 'bi72fccc7184ef45f9',
|
||||
debug: false,
|
||||
autoTrack: true,
|
||||
autoStart: true,
|
||||
appid: ''
|
||||
})
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
componentDidMount () {}
|
||||
|
||||
componentDidShow () {}
|
||||
|
||||
componentDidHide () {}
|
||||
|
||||
// this.props.children 是将要会渲染的页面
|
||||
render () {
|
||||
return this.props.children
|
||||
}
|
||||
|
||||
@@ -1,148 +1,534 @@
|
||||
// 在 src/index.scss 中引入 GitHub Markdown 主题
|
||||
@import "github-markdown-css/github-markdown.css";
|
||||
|
||||
// marktext的换行处理
|
||||
.markdown-body p,
|
||||
.markdown-body blockquote,
|
||||
.markdown-body ul,
|
||||
.markdown-body ol,
|
||||
.markdown-body dl,
|
||||
.markdown-body table,
|
||||
.markdown-body pre,
|
||||
.markdown-body details {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.markdown-body li > p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
// ===== 顶部导航栏 =====
|
||||
.book_header_div {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
height: 88px;
|
||||
}
|
||||
|
||||
.book_header {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
// background-color: aquamarine;
|
||||
// background-color: #f0f5ff;
|
||||
border-bottom: 2px solid #f0f5ff;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
height: 88px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.book_header_left {
|
||||
width: 100px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #69b1ff;
|
||||
color: #1a1a2e;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.book_header_middle {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #69b1ff;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: #1a1a2e;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.book_header_right {
|
||||
width: 100px;
|
||||
// background-color: yellow;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #69b1ff;
|
||||
color: #4facfe;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:active {
|
||||
background: #dceeff;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #4facfe;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pc-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 内容区域 =====
|
||||
.Book {
|
||||
padding: 40px;
|
||||
padding: 30px;
|
||||
max-width: 100%;
|
||||
|
||||
.markdown-body {
|
||||
font-size: 30px;
|
||||
// color: #72d572;
|
||||
font-size: 32px !important;
|
||||
line-height: 1.85 !important;
|
||||
color: #2c3e50 !important;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
h1 {
|
||||
font-size: 48px !important;
|
||||
font-weight: 800;
|
||||
color: #1a1a2e;
|
||||
margin: 48px 0 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid #e8e8e8;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 42px !important;
|
||||
font-weight: 700;
|
||||
color: #2c3e50;
|
||||
margin: 40px 0 20px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 36px !important;
|
||||
font-weight: 600;
|
||||
color: #34495e;
|
||||
margin: 32px 0 16px;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
font-size: 32px !important;
|
||||
font-weight: 600;
|
||||
color: #4a5568;
|
||||
margin: 24px 0 12px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 32px !important;
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.9;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 24px 0;
|
||||
padding: 20px 24px;
|
||||
border-left: 6px solid #4facfe;
|
||||
background: #f8fbff;
|
||||
border-radius: 0 12px 12px 0;
|
||||
color: #4a5568;
|
||||
|
||||
p {
|
||||
margin-bottom: 8px;
|
||||
&:last-child { margin-bottom: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 24px 0;
|
||||
padding: 24px;
|
||||
background: #1e1e2e;
|
||||
border-radius: 12px;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
code {
|
||||
font-family: "SF Mono", "Fira Code", Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 26px !important;
|
||||
line-height: 1.6;
|
||||
color: #e2e8f0;
|
||||
background: none !important;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
white-space: pre;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: "SF Mono", "Fira Code", Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 28px !important;
|
||||
padding: 4px 10px;
|
||||
background: #f1f5f9;
|
||||
color: #e53e3e;
|
||||
border-radius: 6px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 32px !important;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 16px 0;
|
||||
padding-left: 40px;
|
||||
|
||||
li {
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.85;
|
||||
> p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul li { list-style-type: disc; }
|
||||
ol li { list-style-type: decimal; }
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin: 24px 0;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
th {
|
||||
background: #f8fafc;
|
||||
font-weight: 600;
|
||||
padding: 16px 20px;
|
||||
text-align: left;
|
||||
border: 1px solid #e2e8f0;
|
||||
white-space: nowrap;
|
||||
font-size: 28px !important;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 14px 20px;
|
||||
border: 1px solid #e2e8f0;
|
||||
font-size: 28px !important;
|
||||
}
|
||||
|
||||
tr:nth-child(even) { background: #f8fafc; }
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 40px 0;
|
||||
border: none;
|
||||
border-top: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
margin: 24px auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4facfe;
|
||||
text-decoration: none;
|
||||
font-size: inherit !important;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: border-color 0.2s;
|
||||
&:hover { border-bottom-color: #4facfe; }
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
color: #1a1a2e;
|
||||
font-size: inherit !important;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
details {
|
||||
margin: 16px 0;
|
||||
padding: 16px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// img {
|
||||
// max-width: 100%;
|
||||
// height: auto;
|
||||
// /* 保持图像的纵横比 */
|
||||
// }
|
||||
|
||||
img {
|
||||
/* 如果需要让 img 当 flex item 居中,不需要额外样式 */
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
.markdown-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 400px;
|
||||
color: #8c8c8c;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.at-drawer__content {
|
||||
.at-list {
|
||||
.at-list__item {
|
||||
font-size: 30px;
|
||||
// 二维码区域
|
||||
.qrcode-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
// background-color: aqua;
|
||||
.at-list__item-container {
|
||||
.at-list__item-content {
|
||||
// 抽屉目录
|
||||
.book_AtDrawer {
|
||||
.at-drawer__content {
|
||||
background: #fff;
|
||||
padding-top: 88px;
|
||||
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.at-list {
|
||||
.at-list__item {
|
||||
font-size: 30px;
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
color: #2c3e50;
|
||||
transition: background 0.15s;
|
||||
|
||||
&:active {
|
||||
background: #f0f7ff;
|
||||
}
|
||||
|
||||
.at-list__item-container {
|
||||
.at-list__item-content__info-title {
|
||||
font-size: 30px;
|
||||
line-height: 1.5;
|
||||
color: #2c3e50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.at-drawer__mask {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
}
|
||||
|
||||
// 支付按钮
|
||||
.joinSalon {
|
||||
margin-top: 30px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
border-radius: 12px;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
/* stylelint-disable */
|
||||
// ===== Tablet/Desktop: 768px+ =====
|
||||
// 使用 PX (大写) 防止 Taro postcss-pxtransform 转换
|
||||
@media (min-width: 768PX) {
|
||||
.book_header {
|
||||
height: 56PX;
|
||||
|
||||
.book_header_middle {
|
||||
font-size: 18PX;
|
||||
}
|
||||
|
||||
.book_header_right {
|
||||
width: auto;
|
||||
height: 34PX;
|
||||
padding: 0 14PX;
|
||||
margin-right: 16PX;
|
||||
gap: 5PX;
|
||||
border-radius: 17PX;
|
||||
font-size: 13PX;
|
||||
|
||||
&:hover {
|
||||
background: #dceeff;
|
||||
}
|
||||
|
||||
.pc-only {
|
||||
display: inline;
|
||||
font-size: 13PX;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.book_header_div {
|
||||
height: 56PX;
|
||||
}
|
||||
|
||||
.Book {
|
||||
width: 100%;
|
||||
// height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// background-color: yellow;
|
||||
.book_left {
|
||||
width: 400px;
|
||||
height: 100%;
|
||||
background-color: red;
|
||||
padding: 30PX 60PX;
|
||||
|
||||
.book_AtDrawer .at-drawer__content {
|
||||
padding-top: 56PX;
|
||||
width: 300PX;
|
||||
|
||||
.at-list .at-list__item {
|
||||
font-size: 21PX;
|
||||
padding: 14PX 18PX;
|
||||
|
||||
.at-list__item-container .at-list__item-content__info-title {
|
||||
font-size: 21PX;
|
||||
}
|
||||
|
||||
.at-list__item-extra__icon-arrow {
|
||||
font-size: 12PX !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f0f7ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
// width: 100%;
|
||||
width: 700px;
|
||||
// max-width: 1400px;
|
||||
// font-size: 22px;
|
||||
font-size: 18px;
|
||||
font-size: 16PX !important;
|
||||
line-height: 1.8 !important;
|
||||
max-width: 800PX;
|
||||
margin: 0 auto;
|
||||
|
||||
// color: red;
|
||||
// background-color: #72d572;
|
||||
}
|
||||
h1 {
|
||||
font-size: 28PX !important;
|
||||
margin: 32PX 0 16PX;
|
||||
padding-bottom: 10PX;
|
||||
border-bottom-width: 2PX;
|
||||
}
|
||||
|
||||
.book_right {
|
||||
width: 400px;
|
||||
height: 100%;
|
||||
background-color: greenyellow;
|
||||
h2 {
|
||||
font-size: 23PX !important;
|
||||
margin: 26PX 0 12PX;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 19PX !important;
|
||||
margin: 22PX 0 10PX;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
font-size: 16PX !important;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16PX !important;
|
||||
margin-bottom: 14PX;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 16PX !important;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 18PX;
|
||||
border-radius: 8PX;
|
||||
margin: 20PX 0;
|
||||
|
||||
code {
|
||||
font-size: 14PX !important;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 14PX !important;
|
||||
padding: 2PX 6PX;
|
||||
border-radius: 4PX;
|
||||
}
|
||||
|
||||
table th, table td {
|
||||
font-size: 14PX !important;
|
||||
padding: 8PX 12PX;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 14PX 18PX;
|
||||
border-left-width: 4PX;
|
||||
margin: 18PX 0;
|
||||
border-radius: 0 8PX 8PX 0;
|
||||
}
|
||||
|
||||
ul, ol { padding-left: 24PX; }
|
||||
img { border-radius: 8PX; margin: 20PX auto; }
|
||||
hr { margin: 24PX 0; border-top-width: 2PX; }
|
||||
|
||||
a { font-size: inherit !important; border-bottom-width: 1PX; }
|
||||
strong { font-size: inherit !important; }
|
||||
}
|
||||
|
||||
.joinSalon {
|
||||
// width: 100%;
|
||||
// height: 100px;
|
||||
|
||||
display: none;
|
||||
|
||||
// background-color: yellow;
|
||||
max-width: 360PX;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
font-size: 16PX;
|
||||
border-radius: 8PX;
|
||||
}
|
||||
}
|
||||
.Book img {
|
||||
/* 如果需要让 img 当 flex item 居中,不需要额外样式 */
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
// ===== Desktop: 1024px+ =====
|
||||
@media (min-width: 1024PX) {
|
||||
.Book {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 30PX 80PX;
|
||||
|
||||
.markdown-body {
|
||||
width: 720PX;
|
||||
font-size: 17PX !important;
|
||||
line-height: 1.85 !important;
|
||||
|
||||
h1 { font-size: 30PX !important; }
|
||||
h2 { font-size: 25PX !important; }
|
||||
h3 { font-size: 20PX !important; }
|
||||
p { font-size: 17PX !important; }
|
||||
li { font-size: 17PX !important; }
|
||||
|
||||
pre {
|
||||
padding: 18PX 22PX;
|
||||
code { font-size: 14PX !important; }
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 10PX;
|
||||
max-width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.joinSalon {
|
||||
max-width: 280PX;
|
||||
font-size: 15PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Large Desktop: 1536px+ =====
|
||||
@media (min-width: 1536PX) {
|
||||
.Book {
|
||||
.markdown-body {
|
||||
width: 780PX;
|
||||
font-size: 18PX !important;
|
||||
|
||||
h1 { font-size: 32PX !important; }
|
||||
h2 { font-size: 26PX !important; }
|
||||
h3 { font-size: 22PX !important; }
|
||||
p { font-size: 18PX !important; }
|
||||
li { font-size: 18PX !important; }
|
||||
pre code { font-size: 15PX !important; }
|
||||
}
|
||||
|
||||
.joinSalon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* stylelint-enable */
|
||||
|
||||
@@ -1,477 +1,297 @@
|
||||
// @ts-nocheck
|
||||
import { Component } from "react";
|
||||
import { View, Text, Image } from "@tarojs/components";
|
||||
import { View, Image } from "@tarojs/components";
|
||||
import Taro, { useRouter } from "@tarojs/taro";
|
||||
import "./index.scss";
|
||||
import { AtButton, AtInput, AtTabBar } from "taro-ui";
|
||||
import React, { useCallback, useEffect, useState, useRef } from "react";
|
||||
import { AtGrid } from "taro-ui";
|
||||
import { Swiper, SwiperItem } from "@tarojs/components";
|
||||
import { AtCard } from "taro-ui";
|
||||
import { AtImagePicker } from "taro-ui";
|
||||
import { AtAvatar } from "taro-ui";
|
||||
import { AtTag } from "taro-ui";
|
||||
import { AtList, AtListItem } from "taro-ui";
|
||||
import { AtForm, AtMessage, AtDrawer, AtIcon } from "taro-ui";
|
||||
import { AtButton, AtDrawer, AtIcon } from "taro-ui";
|
||||
import React, { useEffect, useState, useRef, useMemo, useCallback } from "react";
|
||||
import { marked } from "marked";
|
||||
import infoText from "./info.md";
|
||||
import bookText from "./book.md";
|
||||
// import youtubeIco from "../../images/youtube.ico";
|
||||
import hackrobot from "../../images/hackrobot.jpg";
|
||||
// PocketBase 配置
|
||||
|
||||
const PB_URL = "https://pocketbase.hackrobot.cn";
|
||||
const pb = new PocketBase(PB_URL);
|
||||
|
||||
marked.setOptions({
|
||||
breaks: true, // 是否回车换行
|
||||
gfm: true, //使用经批准的 GitHub Flavored Markdown (GFM) 规范
|
||||
// pedantic: true, //严格模式
|
||||
// highlight(code:any, lang:any) {
|
||||
// // 语法高亮
|
||||
// let val = code;
|
||||
// if (lang) {
|
||||
// val = hljs.highlight(lang, code).value;
|
||||
// } else {
|
||||
// val = hljs.highlightAuto(code).value;
|
||||
// }
|
||||
// return val;
|
||||
// },
|
||||
marked.setOptions({ breaks: true, gfm: true });
|
||||
|
||||
function addLazyLoadToImages(html) {
|
||||
return html.replace(/<img /g, '<img loading="lazy" decoding="async" ');
|
||||
}
|
||||
|
||||
function splitIntoChunks(html) {
|
||||
const parts = html.split(/(?=<h1[\s>])/i);
|
||||
return parts.filter(p => p.trim().length > 0);
|
||||
}
|
||||
|
||||
function extractHeaders(html) {
|
||||
const regex = /<h1[^>]*>(.*?)<\/h1>/gi;
|
||||
const results = [];
|
||||
let match;
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
results.push(match[1].replace(/<[^>]+>/g, ""));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
const LazyChunk = React.memo(({ html, forceVisible }) => {
|
||||
const [visible, setVisible] = useState(forceVisible);
|
||||
const ref = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (forceVisible) { setVisible(true); return; }
|
||||
if (visible) return;
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
setVisible(true);
|
||||
observer.disconnect();
|
||||
}
|
||||
},
|
||||
{ rootMargin: "800px 0px" }
|
||||
);
|
||||
observer.observe(el);
|
||||
return () => observer.disconnect();
|
||||
}, [forceVisible, visible]);
|
||||
|
||||
if (visible) {
|
||||
return <div dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
}
|
||||
return <div ref={ref} style={{ minHeight: "200px" }} />;
|
||||
});
|
||||
|
||||
// const renderer = new marked.Renderer();
|
||||
// // 使用拓展
|
||||
// marked.use({ renderer });
|
||||
|
||||
// export default class Index extends Component {
|
||||
const Book = () => {
|
||||
const [book, setbook] = useState(window.localStorage.getItem("book"));
|
||||
const [markText, setmarkText] = useState(book == 1 ? bookText : infoText);
|
||||
const [isWeChat, setisWeChat] = useState(false);
|
||||
const [show, setshow] = useState(false);
|
||||
|
||||
const [headers, setHeaders] = useState([]); // 存储所有 <h1> 的内容
|
||||
const contentRef = useRef(null); // 用于获取渲染后的 DOM
|
||||
|
||||
const [paidType, setPaidType] = useState(null); // 新增:支付类型 'vip' | 'book' | null
|
||||
|
||||
// 把这些变量名全部改为 userId
|
||||
const [headers, setHeaders] = useState([]);
|
||||
const contentRef = useRef(null);
|
||||
const [paidType, setPaidType] = useState(null);
|
||||
const [userId, setUserId] = useState(Taro.getStorageSync("userId") || null);
|
||||
const [loading, setLoading] = useState(true); // 新增:加载状态
|
||||
const router = useRouter(); // Taro 3+ 获取路由参数
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [contentReady, setContentReady] = useState(false);
|
||||
const [forceShowAll, setForceShowAll] = useState(false);
|
||||
const router = useRouter();
|
||||
const [vipbook, setVipbook] = useState(false);
|
||||
|
||||
const [vipbook, setVipbook] = useState(false); //是否在vip群打开
|
||||
|
||||
|
||||
// 在组件挂载时检测 referrer
|
||||
useEffect(() => {
|
||||
if (router && router.params && router.params.type === 'vipbook') {
|
||||
setVipbook(true)
|
||||
} else {
|
||||
setVipbook(false)
|
||||
}
|
||||
setVipbook(router?.params?.type === "vipbook");
|
||||
}, []);
|
||||
|
||||
// 保存 userId 到本地
|
||||
const saveUserId = (id) => {
|
||||
Taro.setStorageSync("userId", id);
|
||||
setUserId(id);
|
||||
};
|
||||
|
||||
// 检查本地是否已有支付类型
|
||||
const getLocalPaidType = () => {
|
||||
return Taro.getStorageSync("paidType") || null;
|
||||
};
|
||||
const getLocalPaidType = () => Taro.getStorageSync("paidType") || null;
|
||||
|
||||
// 保存支付类型到本地
|
||||
const savePaidType = (type) => {
|
||||
Taro.setStorageSync("paidType", type);
|
||||
setPaidType(type);
|
||||
};
|
||||
|
||||
// 查询 PocketBase 是否支付过
|
||||
const checkPaymentFromPB = async (userId) => {
|
||||
// window.alert('查询pocketbase')
|
||||
const checkPaymentFromPB = async (uid) => {
|
||||
try {
|
||||
// 查询 payments 表中该 user_id 的记录,按创建时间倒序(最新的一笔)
|
||||
const records = await pb.collection("payments").getList(1, 1, {
|
||||
filter: `user_id = "${userId}"`,
|
||||
sort: "-created", // 最新支付优先
|
||||
filter: `user_id = "${uid}"`,
|
||||
sort: "-created",
|
||||
});
|
||||
|
||||
if (records.items.length > 0) {
|
||||
alert("records.items[0]", records.items[0]);
|
||||
const latestType = records.items[0].type; // 取最新一笔的 type
|
||||
const dbUserId = records.items[0].user_id; // 数据库里的真实 user_id
|
||||
// window.alert('latestType', dbUserId)
|
||||
savePaidType(latestType);
|
||||
|
||||
saveUserId(dbUserId); // 正确保存真实的 user_id
|
||||
console.log("从 PocketBase 查询到已支付:", latestType);
|
||||
return latestType;
|
||||
} else {
|
||||
// window.alert('未找到支付记录')
|
||||
|
||||
console.log("未找到支付记录");
|
||||
savePaidType(null);
|
||||
return null;
|
||||
savePaidType(records.items[0].type);
|
||||
saveUserId(records.items[0].user_id);
|
||||
return records.items[0].type;
|
||||
}
|
||||
savePaidType(null);
|
||||
return null;
|
||||
} catch (err) {
|
||||
// window.alert('查询 PocketBase 失败', err)
|
||||
console.error("查询 PocketBase 失败:", err);
|
||||
// 网络错误时不影响本地缓存,使用本地旧值
|
||||
return getLocalPaidType();
|
||||
} finally {
|
||||
}
|
||||
};
|
||||
|
||||
// 清空所有本地存储(测试专用)
|
||||
const clearAllStorage = () => {
|
||||
try {
|
||||
// 清空 Taro 的 storage(推荐方式)
|
||||
Taro.clearStorageSync();
|
||||
|
||||
// 同时清空 window.localStorage(H5 环境兼容)
|
||||
if (typeof window !== "undefined" && window.localStorage) {
|
||||
window.localStorage.clear();
|
||||
}
|
||||
|
||||
// 可选:手动清除你知道的关键字段,防止残留
|
||||
Taro.removeStorageSync("userId");
|
||||
Taro.removeStorageSync("paidType");
|
||||
Taro.removeStorageSync("openid");
|
||||
Taro.removeStorageSync("wxid");
|
||||
|
||||
// 状态重置
|
||||
setPaidType(null);
|
||||
setUserName(null);
|
||||
setLoading(false);
|
||||
|
||||
Taro.showToast({
|
||||
title: "本地存储已清空",
|
||||
icon: "success",
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
// 可选:刷新页面让效果立即生效
|
||||
setTimeout(() => {
|
||||
// window.location.reload();
|
||||
}, 1000);
|
||||
Taro.showToast({ title: "本地存储已清空", icon: "success", duration: 2000 });
|
||||
} catch (error) {
|
||||
console.error("清空存储失败:", error);
|
||||
Taro.showToast({
|
||||
title: "清空存储失败",
|
||||
icon: "none",
|
||||
});
|
||||
Taro.showToast({ title: "清空存储失败", icon: "none" });
|
||||
}
|
||||
};
|
||||
|
||||
const isWeChatFun = () => {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
const result = ua.includes("micromessenger");
|
||||
setisWeChat(result);
|
||||
return result;
|
||||
};
|
||||
|
||||
const getOrCreateUserId = () => {
|
||||
let id = Taro.getStorageSync("userId");
|
||||
if (!id) {
|
||||
id = `user${Date.now()}`;
|
||||
Taro.setStorageSync("userId", id);
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// 判断是否在微信
|
||||
isWeChatFun();
|
||||
// 方法1:Taro 3+ 推荐方式(支持小程序 + H5)
|
||||
if (router && router.params && router.params.type === "clean") {
|
||||
if (router?.params?.type === "clean") {
|
||||
clearAllStorage();
|
||||
return;
|
||||
}
|
||||
|
||||
const init = async () => {
|
||||
const currentUserId = getOrCreateUserId(); // 确保 userId 存在
|
||||
|
||||
const currentUserId = getOrCreateUserId();
|
||||
const localType = getLocalPaidType();
|
||||
const localUserId = Taro.getStorageSync("userId");
|
||||
|
||||
// 只有当本地同时有 paidType 和 userId 时,才信任本地缓存
|
||||
if (localType && localUserId) {
|
||||
setPaidType(localType);
|
||||
setUserId(localUserId);
|
||||
setLoading(false);
|
||||
console.log("使用本地缓存支付状态:", localType);
|
||||
return;
|
||||
}
|
||||
|
||||
// 否则去 PocketBase 查最新状态
|
||||
await checkPaymentFromPB(currentUserId);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
init();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (contentRef.current) {
|
||||
const handleJump = useCallback((text) => {
|
||||
setForceShowAll(true);
|
||||
setTimeout(() => {
|
||||
if (!contentRef.current) return;
|
||||
const h1Elements = contentRef.current.querySelectorAll("h1");
|
||||
const h2Elements = contentRef.current.querySelectorAll("h2");
|
||||
|
||||
const h1Texts = Array.from(h1Elements).map((el) => el.textContent);
|
||||
const h2Texts = Array.from(h2Elements).map((el) => el.textContent);
|
||||
|
||||
setHeaders(h1Texts);
|
||||
// console.log("获取到的 H1 标题:"); // 控制台查看
|
||||
console.log("获取到的 H1 标题:", h1Texts); // 控制台查看
|
||||
console.log("获取到的 H2 标题:", h2Texts); // 控制台查看
|
||||
}
|
||||
}, [markText]); // 监听 HTML 内容变化
|
||||
|
||||
const handleJump = (text) => {
|
||||
const h1Elements = contentRef.current.querySelectorAll("h1");
|
||||
for (let h1 of h1Elements) {
|
||||
if (h1.textContent.trim() === text.trim()) {
|
||||
// if (h1.textContent === text) {
|
||||
h1.scrollIntoView({ behavior: "smooth" });
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// const handleClick = (value) => {
|
||||
// // 跳转到目的页面,在当前页面打开
|
||||
// Taro.navigateTo({
|
||||
// url: "/pages/index/index",
|
||||
// });
|
||||
// };
|
||||
|
||||
// 是否在微信客户端
|
||||
const isWeChatFun = () => {
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.indexOf("micromessenger") != -1) {
|
||||
setisWeChat(true);
|
||||
return true;
|
||||
} else {
|
||||
setisWeChat(false);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const payh51111 = (type, total_fee = 1000) => {
|
||||
Taro.request({
|
||||
method: "POST",
|
||||
url: `${process.env.TARO_API_API}/payh5`,
|
||||
data: {
|
||||
total_fee: total_fee,
|
||||
type: type,
|
||||
// callback_url 临时不传
|
||||
},
|
||||
header: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.data?.status === "ok" && res.data?.xorpay_params) {
|
||||
// 创建隐藏 form POST 到 XorPay
|
||||
const form = document.createElement("form");
|
||||
form.method = "POST";
|
||||
form.action = res.data.xorpay_url;
|
||||
form.style.display = "none";
|
||||
|
||||
for (const key in res.data.xorpay_params) {
|
||||
const input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = key;
|
||||
input.value = res.data.xorpay_params[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
} else {
|
||||
Taro.showToast({
|
||||
title: "支付发起失败",
|
||||
icon: "none",
|
||||
});
|
||||
for (let h1 of h1Elements) {
|
||||
if (h1.textContent.trim() === text.trim()) {
|
||||
h1.scrollIntoView({ behavior: "smooth" });
|
||||
break;
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
Taro.showToast({
|
||||
title: "网络错误",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
}, 150);
|
||||
}, []);
|
||||
|
||||
// 生成或获取 userId(修改为无下划线)
|
||||
const getOrCreateUserId = () => {
|
||||
let userId = Taro.getStorageSync("userId");
|
||||
if (!userId) {
|
||||
// 修改这里:去掉下划线
|
||||
userId = `user${Date.now()}`; // 示例:user1766043770158
|
||||
Taro.setStorageSync("userId", userId);
|
||||
console.log("新生成 userId:", userId);
|
||||
const submitPayForm = (xorpayUrl, xorpayParams) => {
|
||||
const form = document.createElement("form");
|
||||
form.method = "POST";
|
||||
form.action = xorpayUrl;
|
||||
form.style.display = "none";
|
||||
for (const key in xorpayParams) {
|
||||
const input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = key;
|
||||
input.value = xorpayParams[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
return userId;
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
setTimeout(() => document.body.removeChild(form), 1000);
|
||||
};
|
||||
|
||||
const payh5 = (type, total_fee = 1000) => {
|
||||
const userId = getOrCreateUserId(); // ← 新增:获取 userId
|
||||
const uid = getOrCreateUserId();
|
||||
Taro.request({
|
||||
method: "POST",
|
||||
url: `${process.env.TARO_API_API}/payh5`,
|
||||
data: {
|
||||
total_fee: total_fee,
|
||||
type: type,
|
||||
// callback_url 临时不传
|
||||
user_id: userId, // ← 新增字段
|
||||
},
|
||||
header: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
data: { total_fee, type, user_id: uid },
|
||||
header: { "content-type": "application/json" },
|
||||
success: (res) => {
|
||||
if (res.data?.status === "ok" && res.data?.xorpay_params) {
|
||||
// 1. 乐观更新:立即缓存 paidType,用户看到“加载中”或直接显示已支付
|
||||
// savePaidType(type);
|
||||
// saveUserName(userId); // ← 乐观缓存当前 userId
|
||||
// Taro.showToast({
|
||||
// title: "正在跳转支付,请稍后...",
|
||||
// icon: "loading",
|
||||
// duration: 2000,
|
||||
// });
|
||||
|
||||
// 创建隐藏 form POST 到 XorPay
|
||||
const form = document.createElement("form");
|
||||
form.method = "POST";
|
||||
form.action = res.data.xorpay_url;
|
||||
form.style.display = "none";
|
||||
|
||||
for (const key in res.data.xorpay_params) {
|
||||
const input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = key;
|
||||
input.value = res.data.xorpay_params[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
|
||||
// 2. 可选:提交后清理 form,避免内存泄漏
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(form);
|
||||
}, 1000);
|
||||
submitPayForm(res.data.xorpay_url, res.data.xorpay_params);
|
||||
} else {
|
||||
Taro.showToast({
|
||||
title: "支付发起失败",
|
||||
icon: "none",
|
||||
});
|
||||
Taro.showToast({ title: "支付发起失败", icon: "none" });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
Taro.showToast({
|
||||
title: "网络错误",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
fail: () => Taro.showToast({ title: "网络错误", icon: "none" }),
|
||||
});
|
||||
};
|
||||
|
||||
const isPaid = paidType === "book" || vipbook;
|
||||
|
||||
const markdownSource = isPaid ? bookText : infoText;
|
||||
const parsedHtml = useMemo(() => addLazyLoadToImages(marked(markdownSource)), [markdownSource]);
|
||||
const chunks = useMemo(() => splitIntoChunks(parsedHtml), [parsedHtml]);
|
||||
const headerList = useMemo(() => extractHeaders(parsedHtml), [parsedHtml]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) return;
|
||||
setHeaders(headerList);
|
||||
const raf = requestAnimationFrame(() => {
|
||||
setContentReady(true);
|
||||
});
|
||||
return () => cancelAnimationFrame(raf);
|
||||
}, [loading, headerList]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className="book_header_div"></View>
|
||||
<View className="book_header_div" />
|
||||
<View className="book_header">
|
||||
<View
|
||||
className="book_header_left"
|
||||
onClick={() => {
|
||||
Taro.redirectTo({
|
||||
url: `/`,
|
||||
});
|
||||
// Taro.navigateBack({
|
||||
// delta: 1, // 表示返回的页面数,默认是 1,表示返回上一页
|
||||
// });
|
||||
}}
|
||||
>
|
||||
<AtIcon value="chevron-left"></AtIcon>
|
||||
<View className="book_header_left" onClick={() => Taro.redirectTo({ url: "/" })}>
|
||||
<AtIcon value="chevron-left" />
|
||||
</View>
|
||||
<View className="book_header_middle">{`数字游民`}</View>
|
||||
<View
|
||||
className="book_header_right"
|
||||
onClick={() => {
|
||||
setshow(!show);
|
||||
}}
|
||||
>
|
||||
<AtIcon value="bullet-list"></AtIcon>
|
||||
<View className="book_header_middle">数字游民</View>
|
||||
<View className={`book_header_right ${show ? 'active' : ''}`} onClick={() => setshow(!show)}>
|
||||
<AtIcon value="bullet-list" />
|
||||
<View className="book_header_right_text pc-only">目录</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="Book">
|
||||
<View
|
||||
ref={contentRef}
|
||||
className="markdown-body" // 添加 GitHub Markdown 主题类
|
||||
dangerouslySetInnerHTML={{
|
||||
// __html: marked(markText),
|
||||
// __html: marked(book == 1 ? bookText : infoText),
|
||||
__html: marked(paidType=='book'|| vipbook ? bookText : infoText),
|
||||
|
||||
}}
|
||||
></View>
|
||||
<View className="Book">
|
||||
{!contentReady ? (
|
||||
<View className="markdown-loading">加载中...</View>
|
||||
) : (
|
||||
<View ref={contentRef} className="markdown-body">
|
||||
{chunks.map((chunk, i) => (
|
||||
<LazyChunk
|
||||
key={i}
|
||||
html={chunk}
|
||||
forceVisible={forceShowAll || i === 0}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
|
||||
<AtDrawer
|
||||
className="book_AtDrawer"
|
||||
show={show}
|
||||
mask
|
||||
items={headers}
|
||||
onItemClick={(index) => {
|
||||
handleJump(headers[index]);
|
||||
}}
|
||||
onClose={() => {
|
||||
setshow(false);
|
||||
}}
|
||||
>
|
||||
<View className="drawer-item"></View>
|
||||
{/* <View className="drawer-item">如果items没有数据就会展示children</View> */}
|
||||
{/* <View className="drawer-item">
|
||||
这是自定义内容 <AtIcon value="home" size="20" />
|
||||
</View> */}
|
||||
</AtDrawer>
|
||||
onItemClick={(index) => handleJump(headers[index])}
|
||||
onClose={() => setshow(false)}
|
||||
/>
|
||||
|
||||
{/* 判断是否是微信 */}
|
||||
{!isWeChat && (
|
||||
// 公众号二维码
|
||||
<div
|
||||
style={{
|
||||
color: "red",
|
||||
display: "flex", // 关键:flex 布局
|
||||
justifyContent: "center", // 水平居中
|
||||
alignItems: "center", // 垂直居中(可选,如果你想整块垂直也居中)
|
||||
flexDirection: "column", // 可选:让内容垂直排列(如果下面还有文字)
|
||||
margin: "20px 0", // 可选:上下留点间距
|
||||
}}
|
||||
>
|
||||
<View className="qrcode-section">
|
||||
<Image
|
||||
className="hackrobot"
|
||||
src={hackrobot}
|
||||
style={{
|
||||
width: "300px",
|
||||
height: "300px",
|
||||
maxWidth: "none",
|
||||
maxHeight: "none",
|
||||
}}
|
||||
// src={`https://minioweb.hackrobot.cn/hackrobot/propless.svg`}
|
||||
style={{ width: "300px", height: "300px" }}
|
||||
lazyLoad
|
||||
></Image>
|
||||
</div>
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 判断有没有wxid */}
|
||||
{/* {book != 1 ? ( */}
|
||||
{paidType != "book" && !vipbook ? (
|
||||
{!isPaid && (
|
||||
<AtButton
|
||||
type="primary"
|
||||
size="normal"
|
||||
className="joinSalon"
|
||||
onClick={() => {
|
||||
if (paidType == "book" || vipbook) {
|
||||
return false;
|
||||
if (isWeChat) {
|
||||
payh5("book", 4900);
|
||||
} else {
|
||||
if (!!isWeChat) {
|
||||
//49元
|
||||
payh5("book", 4900);
|
||||
// window.location.href = `https://vip.hackrobot.cn`;
|
||||
} else {
|
||||
window.location.href = `https://mp.weixin.qq.com/s/PBbnS8qC_kqhL9HJO5m-Iw`;
|
||||
}
|
||||
window.location.href = "https://mp.weixin.qq.com/s/PBbnS8qC_kqhL9HJO5m-Iw";
|
||||
}
|
||||
}}
|
||||
>
|
||||
{`🔒阅读更多`}
|
||||
阅读更多
|
||||
</AtButton>
|
||||
) : // <span style={{ color: "green" }}>持续更新中....</span>
|
||||
null}
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,504 +1,112 @@
|
||||
import { Component } from "react";
|
||||
import Taro,{useRouter} from "@tarojs/taro";
|
||||
import { View, Text, Image, Button } from "@tarojs/components";
|
||||
import Taro, { useRouter } from "@tarojs/taro";
|
||||
import { View, Image } from "@tarojs/components";
|
||||
import "./index.scss";
|
||||
import { AtTabBar } from "taro-ui";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { AtGrid } from "taro-ui";
|
||||
import { Swiper, SwiperItem } from "@tarojs/components";
|
||||
import { AtCard } from "taro-ui";
|
||||
import { AtImagePicker } from "taro-ui";
|
||||
import { AtButton } from "taro-ui";
|
||||
import { AtSearchBar } from "taro-ui";
|
||||
import { Picker } from "@tarojs/components";
|
||||
import { AtList, AtListItem, AtNavBar, AtTag, AtMessage } from "taro-ui";
|
||||
import {
|
||||
AtModal,
|
||||
AtModalHeader,
|
||||
AtModalContent,
|
||||
AtModalAction,
|
||||
AtAvatar,
|
||||
AtAccordion,
|
||||
} from "taro-ui";
|
||||
import { AtToast } from "taro-ui";
|
||||
import { AtIcon } from "taro-ui";
|
||||
import { VIEW } from "@tarojs/runtime";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import "animate.css";
|
||||
import touxiang from "../../images/touxiang.png";
|
||||
import cat from "../../images/cat.jpg";
|
||||
import girl from "../../images/girl.jpg";
|
||||
|
||||
import emoji from "../../images/emoji.png";
|
||||
import phone from "../../images/phone.png";
|
||||
// import robot from "../../images/robot.png";
|
||||
import nomad from "../../images/nomad.png";
|
||||
// import book from "../../images/book.png";
|
||||
import qrcode from "../../images/qrcode.png";
|
||||
|
||||
import meetup from "../../images/meetup.jpg";
|
||||
import bookqr from "../../images/bookqr.jpg";
|
||||
import loft from "../../images/loft.png";
|
||||
import AIGC from "../../images/AIGC.png";
|
||||
import robot192 from "../../images/robot192.png";
|
||||
// import youtube from "../../images/youtube.svg";
|
||||
import ssh from "../../images/ssh.svg";
|
||||
import robot from "../../images/robot.svg";
|
||||
import host from "../../images/host.svg";
|
||||
import ytGpt from "../../images/ytGpt.png";
|
||||
|
||||
import demo from "../../images/demo.svg";
|
||||
import AI from "../../images/AI.png";
|
||||
import nomadro from "../../images/nomadro.png";
|
||||
import phone2 from "../../images/phone2.png";
|
||||
|
||||
import code from "../../images/code.svg";
|
||||
import laptop from "../../images/laptop.svg";
|
||||
import travel from "../../images/travel.svg";
|
||||
import group from "../../images/group.svg";
|
||||
import book from "../../images/book.svg";
|
||||
import youtubesvg from "../../images/youtube.svg";
|
||||
import dgnomad from "../../images/dgnomad.png";
|
||||
import tiktok from "../../images/tiktok.png";
|
||||
import youtube from "../../images/youtube.png";
|
||||
import web from "../../images/web.png";
|
||||
|
||||
|
||||
// export default class Index extends Component {
|
||||
const Index = () => {
|
||||
const [current, setcurrent] = useState(0);
|
||||
const [openId, setopenId] = useState(null);
|
||||
const [wxid, setwxid] = useState(null);
|
||||
const [userInfo, setuserInfo] = useState({});
|
||||
const [vipbook, setVipbook] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const [open, setopen] = useState(false);
|
||||
// const [referer, setreferer] = useState(window.document.referrer);
|
||||
const [referer, setreferer] = useState("");
|
||||
|
||||
|
||||
const [isOpened, setisOpened] = useState(false);
|
||||
const [meetupQR, setmeetupQR] = useState(false);
|
||||
|
||||
const [bookToast, setbookToast] = useState(false);
|
||||
const [meetupToast, setmeetupToast] = useState(false);
|
||||
|
||||
const [joinMeetup, setjoinMeetup] = useState(false);
|
||||
const [bookpay, setbookpay] = useState(0);
|
||||
|
||||
const [isWeChat, setisWeChat] = useState(false);
|
||||
const [vipbook, setVipbook] = useState(false); //是否在vip群打开
|
||||
|
||||
const router = useRouter(); // Taro 3+ 获取路由参数
|
||||
|
||||
// 在组件挂载时检测 referrer
|
||||
useEffect(() => {
|
||||
if (router && router.params && router.params.type === 'vipbook') {
|
||||
setVipbook(true)
|
||||
} else {
|
||||
setVipbook(false)
|
||||
}
|
||||
setVipbook(router?.params?.type === "vipbook");
|
||||
}, [router.params]);
|
||||
|
||||
const getOpenidFromUrl = (url) => {
|
||||
const pattern = /[?&]openid=([^&#]+)/;
|
||||
const match = url.match(pattern);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 是否在微信客户端
|
||||
const isWeChatFun = () => {
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.indexOf("micromessenger") != -1) {
|
||||
setisWeChat(true);
|
||||
return true;
|
||||
} else {
|
||||
setisWeChat(false);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取openid
|
||||
const getOpenid = () => {
|
||||
// let newparams = Taro.getCurrentInstance().router.params;
|
||||
// let urlopenid = newparams.openid;
|
||||
|
||||
// hash模式
|
||||
// http://192.168.31.245:10086/?openid=o7LFAwR32hWGq9XOpd7ZxK1wZxq8#/pages/index/index
|
||||
let hashopenid = null;
|
||||
if (window.location.href.includes("openid")) {
|
||||
hashopenid = getOpenidFromUrl(window.location.href);
|
||||
} else {
|
||||
// hashopenid = window.localStorage.getItem("openid");
|
||||
}
|
||||
if (!!hashopenid && hashopenid != "undefined" && hashopenid != "null") {
|
||||
// 获取到openid
|
||||
window.localStorage.setItem("openid", hashopenid);
|
||||
setopenId(hashopenid);
|
||||
|
||||
// window.alert(hashopenid);
|
||||
// 查询数据库是否存在openid
|
||||
Taro.request({
|
||||
method: "GET",
|
||||
url: `${process.env.TARO_API_API}/user/${hashopenid}`, //仅为示例,并非真实的接口地址
|
||||
// url: `${process.env.TARO_API_API}/user/${window.localStorage.getItem("openid")}`, //仅为示例,并非真实的接口地址
|
||||
success: function (res) {
|
||||
if (res?.data?.userInfo) {
|
||||
// 有完整的用户信息userInfo
|
||||
setuserInfo(res?.data?.userInfo);
|
||||
window.localStorage.setItem("userInfo", userInfo);
|
||||
}
|
||||
},
|
||||
complete: function (finy) {
|
||||
// 获取wxid参数
|
||||
getWxidFromUrl();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// let nowUrl = window.location.href;
|
||||
// window.localStorage.removeItem("openid");
|
||||
// // let payUrl = `https://payjs.cn/api/openid?mchid=1561724891&callback_url=${nowUrl}`;
|
||||
// let payUrl = `https://xorpay.com/api/openid/8220&callback_url=${nowUrl}`;
|
||||
// window.location.href = payUrl;
|
||||
|
||||
// 清除旧 openid(可选,建议保留)
|
||||
window.localStorage.removeItem("openid");
|
||||
|
||||
// 当前完整 URL(包括 ? 参数和 # hash)
|
||||
let nowUrl = window.location.href;
|
||||
|
||||
// 正确构造 XorPay openid 获取地址
|
||||
// 1. 参数名必须是 callback
|
||||
// 2. 值必须 encodeURIComponent 编码
|
||||
let payUrl = `https://xorpay.com/api/openid/8220?callback=${encodeURIComponent(
|
||||
nowUrl
|
||||
)}`;
|
||||
|
||||
console.log("跳转获取 openid 的 URL:", payUrl);
|
||||
// 示例输出:https://xorpay.com/api/openid/8220?callback=http%3A%2F%2F192.168.31.222%3A10086%2F%23%2Fpay
|
||||
|
||||
// window.location.href = payUrl;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取更新用户信息
|
||||
const getUserinfo = (wxid) => {
|
||||
Taro.request({
|
||||
method: "GET",
|
||||
url: `${process.env.TARO_API_API}/user/${wxid}`, //仅为示例,并非真实的接口地址
|
||||
// url: `${process.env.TARO_API_API}/user/${window.localStorage.getItem("openid")}`, //仅为示例,并非真实的接口地址
|
||||
success: function (res) {
|
||||
if (res?.data?.userInfo) {
|
||||
//判断wxid是否存在
|
||||
if (res?.data?.userInfo?.openid) {
|
||||
// 有完整的用户信息userInfo
|
||||
setuserInfo(res?.data?.userInfo);
|
||||
window.localStorage.setItem("userInfo", userInfo);
|
||||
}
|
||||
}
|
||||
},
|
||||
complete: function (finy) { },
|
||||
});
|
||||
};
|
||||
|
||||
// 获取url中的wxid
|
||||
const getWxidFromUrl = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const urlwxid = urlParams.get("wxid");
|
||||
if (!!urlwxid) {
|
||||
setwxid(urlwxid);
|
||||
window.localStorage.setItem("wxid", wxid);
|
||||
// 优先查询openid是否存在数据库
|
||||
Taro.request({
|
||||
method: "GET",
|
||||
url: `${process.env.TARO_API_API}/user/${urlwxid}`, //仅为示例,并非真实的接口地址
|
||||
// url: `${process.env.TARO_API_API}/user/${window.localStorage.getItem("openid")}`, //仅为示例,并非真实的接口地址
|
||||
success: function (res) {
|
||||
if (res?.data?.userInfo) {
|
||||
//判断wxid是否存在
|
||||
if (res?.data?.userInfo?.openid) {
|
||||
// window.alert(res?.data?.userInfo?.openid);
|
||||
// window.alert(window.localStorage.getItem("openid"));
|
||||
|
||||
if (
|
||||
res?.data?.userInfo?.openid !==
|
||||
window.localStorage.getItem("openid")
|
||||
) {
|
||||
// 删除其他用户的wxid
|
||||
window.localStorage.removeItem("userInfo");
|
||||
window.localStorage.removeItem("openid");
|
||||
window.localStorage.removeItem("wxid");
|
||||
window.location.href = "https://hackrobot.cn";
|
||||
} else {
|
||||
// 有完整的用户信息userInfo
|
||||
setuserInfo(res?.data?.userInfo);
|
||||
window.localStorage.setItem("userInfo", userInfo);
|
||||
}
|
||||
} else {
|
||||
// 绑定wxid与openid到数据库
|
||||
wxidTapopenid(urlwxid);
|
||||
}
|
||||
} else {
|
||||
// 新增wxid用户
|
||||
}
|
||||
},
|
||||
complete: function (finy) {
|
||||
// tg消息通知
|
||||
// tgMessage();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// tg消息通知
|
||||
// tgMessage();
|
||||
}
|
||||
return wxid;
|
||||
};
|
||||
|
||||
// 绑定wxid与openid
|
||||
const wxidTapopenid = (newWxid) => {
|
||||
const userUpdateData = {
|
||||
openid: window.localStorage.getItem("openid"), // 只更新 openid 字段
|
||||
};
|
||||
Taro.request({
|
||||
method: "PUT",
|
||||
// url: `${process.env.TARO_API_API}/user/${urlwxid}`, //仅为示例,并非真实的接口地址
|
||||
url: `${process.env.TARO_API_API}/user/${newWxid}`, //仅为示例,并非真实的接口地址
|
||||
data: userUpdateData,
|
||||
header: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
success: function (res) { },
|
||||
fail: function (err) { },
|
||||
complete: function (finy) { },
|
||||
});
|
||||
};
|
||||
|
||||
// 新增openid用户
|
||||
const addopenidUser = () => {
|
||||
const userUpdateData = {
|
||||
openid: window.localStorage.getItem("openid"), // 只更新 openid 字段
|
||||
};
|
||||
Taro.request({
|
||||
method: "GET",
|
||||
// url: `${process.env.TARO_API_API}/user/${urlwxid}`, //仅为示例,并非真实的接口地址
|
||||
url: `${process.env.TARO_API_API}/user/${window.localStorage.getItem(
|
||||
"openid"
|
||||
)}`, //仅为示例,并非真实的接口地址
|
||||
data: userUpdateData,
|
||||
header: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
success: function (res) { },
|
||||
fail: function (err) { },
|
||||
complete: function (finy) { },
|
||||
});
|
||||
};
|
||||
|
||||
// 网页查看通知
|
||||
const tgMessage = () => {
|
||||
Taro.request({
|
||||
method: "GET",
|
||||
url: `${process.env.TARO_API_API
|
||||
}/tgMessage?openid=${window.localStorage.getItem("openid")}`, //仅为示例,并非真实的接口地址
|
||||
// url: "https://pay.hackrobot.cn${process.env.TARO_API_API}/payh5", //仅为示例,并非真实的接口地址
|
||||
success: function (res) {
|
||||
console.log("访问提醒发送成功");
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 入群申请
|
||||
|
||||
useEffect(() => {
|
||||
let inwechat = isWeChatFun();
|
||||
if (inwechat) {
|
||||
// 获取openId
|
||||
// getOpenid();
|
||||
} else {
|
||||
// window.alert('不在微信')
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// alert(window.localStorage.getItem("bookpay"))
|
||||
setbookpay(window.localStorage.getItem("bookpay"));
|
||||
}, []);
|
||||
|
||||
const goBack = () => {
|
||||
Taro.navigateBack({});
|
||||
};
|
||||
|
||||
const handleClick = (value) => {
|
||||
// window.alert(value)
|
||||
setopen(value);
|
||||
};
|
||||
|
||||
|
||||
const goRead2 = () => {
|
||||
Taro.navigateTo({
|
||||
url: "/pages/book/index",
|
||||
});
|
||||
};
|
||||
const goRead = () => {
|
||||
// 极简:直接用 router.params 构建参数字符串(无参数时自动为空)
|
||||
const paramsStr = router.params
|
||||
? '?' + new URLSearchParams(router.params).toString()
|
||||
: '';
|
||||
|
||||
Taro.navigateTo({
|
||||
url: `/pages/book/index${paramsStr}`,
|
||||
});
|
||||
};
|
||||
const paramsStr = router.params
|
||||
? "?" + new URLSearchParams(router.params).toString()
|
||||
: "";
|
||||
Taro.navigateTo({ url: `/pages/book/index${paramsStr}` });
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className="index">
|
||||
{/* 在线图书 */}
|
||||
<View className="index">
|
||||
<View className="index-book animate__animated animate__pulse">
|
||||
<View className="index_book_left">
|
||||
<View className="left_title">《数字游民:地理套利与自动化》</View>
|
||||
<View className="left_subtitle">边旅行边赚钱 · 杠杆主义 · 地理套利</View>
|
||||
|
||||
{/* 参考资料https://readmake.com/ */}
|
||||
<View className="index-book animate__animated animate__pulse">
|
||||
<View className="index_book_left">
|
||||
<View className="left_title">《数字游民:地理套利与自动化》</View>
|
||||
{/* <View className="left_title">《云手机》</View> */}
|
||||
|
||||
{/* <View className="left_text">手册3</View> */}
|
||||
{/* <View className="left_mobile">
|
||||
<Text>🚀 边旅行转赚钱</Text>
|
||||
<Text>1️⃣ 杠杆:媒体与代码</Text>
|
||||
<Text>2️⃣ 出海:地理套利</Text>
|
||||
<Text>3️⃣ 即时业务:一夜之间上线网站</Text>
|
||||
<Text>4️⃣ homelab:你的全球总部</Text>
|
||||
<Text>5️⃣ 远程团队:分布式协作</Text>
|
||||
<Text>5️⃣ -----------------</Text>
|
||||
|
||||
<Text>🔥 一起实践,交流</Text>
|
||||
</View> */}
|
||||
|
||||
{/* 卡片 */}
|
||||
<View className="card">
|
||||
<View className="cardItem">
|
||||
<View className="cardItem_left">
|
||||
<Image
|
||||
className="cardItem_left_img youtubeSvg"
|
||||
// src={travel}
|
||||
src={tiktok}
|
||||
|
||||
// src={`https://minioweb.hackrobot.cn/hackrobot/travel.svg`}
|
||||
lazyLoad
|
||||
></Image>
|
||||
</View>
|
||||
<View className="cardItem_right">
|
||||
<View className="cardItem_rightUp">Tiktok</View>
|
||||
<View className="cardItem_rightDown">无人直播</View>
|
||||
</View>
|
||||
<View className="card">
|
||||
<View className="cardItem">
|
||||
<View className="cardItem_left">
|
||||
<Image className="cardItem_left_img" src={tiktok} lazyLoad />
|
||||
</View>
|
||||
<View className="cardItem">
|
||||
<View className="cardItem_left">
|
||||
<Image
|
||||
className="cardItem_left_img"
|
||||
// src={laptop}
|
||||
src={youtube}
|
||||
|
||||
// src={`https://minioweb.hackrobot.cn/hackrobot/laptop.svg`}
|
||||
lazyLoad
|
||||
></Image>
|
||||
</View>
|
||||
<View className="cardItem_right">
|
||||
<View className="cardItem_rightUp">Youtube</View>
|
||||
<View className="cardItem_rightDown">自媒体</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="cardItem">
|
||||
<View className="cardItem_left">
|
||||
<Image
|
||||
className="cardItem_left_img"
|
||||
// src={group}
|
||||
src={web}
|
||||
|
||||
// src={`https://minioweb.hackrobot.cn/hackrobot/propless.svg`}
|
||||
lazyLoad
|
||||
></Image>
|
||||
</View>
|
||||
<View className="cardItem_right">
|
||||
<View className="cardItem_rightUp">web</View>
|
||||
<View className="cardItem_rightDown">saas+web3</View>
|
||||
</View>
|
||||
<View className="cardItem_right">
|
||||
<View className="cardItem_rightUp">Tiktok</View>
|
||||
<View className="cardItem_rightDown">无人直播</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="left_btn ">
|
||||
<AtButton
|
||||
onClick={() => {
|
||||
goRead();
|
||||
}}
|
||||
className="startRead"
|
||||
type="primary"
|
||||
size="small"
|
||||
circle
|
||||
>
|
||||
开始阅读
|
||||
</AtButton>
|
||||
<View className="cardItem">
|
||||
<View className="cardItem_left">
|
||||
<Image className="cardItem_left_img" src={youtube} lazyLoad />
|
||||
</View>
|
||||
<View className="cardItem_right">
|
||||
<View className="cardItem_rightUp">Youtube</View>
|
||||
<View className="cardItem_rightDown">自媒体</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="cardItem">
|
||||
<View className="cardItem_left">
|
||||
<Image className="cardItem_left_img" src={web} lazyLoad />
|
||||
</View>
|
||||
<View className="cardItem_right">
|
||||
<View className="cardItem_rightUp">Web</View>
|
||||
<View className="cardItem_rightDown">SaaS + Web3</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="index_book_img">
|
||||
<Image
|
||||
className="book_img"
|
||||
// src={phone2}
|
||||
src={dgnomad}
|
||||
// src="https://minioweb.hackrobot.cn/hackrobot/phone2.png"
|
||||
fetchpriority="high" // ✅ 提示浏览器尽快下载
|
||||
decoding="async" // ✅ 异步解码,加快渲染
|
||||
lazyLoad={false} // ✅ 禁止延迟加载(LCP 图必须优先加载)
|
||||
alt="云手机封面"
|
||||
/>
|
||||
|
||||
<View className="left_btn">
|
||||
<AtButton
|
||||
onClick={goRead}
|
||||
className="startRead"
|
||||
type="primary"
|
||||
size="small"
|
||||
circle
|
||||
>
|
||||
开始阅读
|
||||
</AtButton>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="svgItems">
|
||||
<View className="svgItem">
|
||||
<View className="bookImg">
|
||||
<Image
|
||||
// style="width: 40%px;height:100%;background: #fff;"
|
||||
// src={book}
|
||||
src={laptop}
|
||||
// src={phone2}
|
||||
// src={tiktok}
|
||||
|
||||
lazyLoad
|
||||
/>
|
||||
<View className="bookImg_text">Tiktok无人直播</View>
|
||||
</View>
|
||||
|
||||
<View className="bookImg">
|
||||
<Image
|
||||
// style="width: 40%px;height:100%;background: #fff;"
|
||||
// src={book}
|
||||
src={travel}
|
||||
// src={youtube}
|
||||
|
||||
lazyLoad
|
||||
/>
|
||||
<View className="bookImg_text">Youtube自媒体</View>
|
||||
</View>
|
||||
<View className="bookImg">
|
||||
<Image
|
||||
// style="width: 40%px;height:100%;background: #fff;"
|
||||
// src={book}
|
||||
src={code}
|
||||
// src={web}
|
||||
lazyLoad
|
||||
/>
|
||||
<View className="bookImg_text">web:saas+web3</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="index_book_img">
|
||||
<Image
|
||||
className="book_img"
|
||||
src={dgnomad}
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
lazyLoad={false}
|
||||
alt="数字游民封面"
|
||||
/>
|
||||
</View>
|
||||
{/* <View className="footer">
|
||||
<View>Copyright © 2025 </View>
|
||||
</View> */}
|
||||
</View>
|
||||
{/* <View className="footer_div"></View> */}
|
||||
</>
|
||||
|
||||
<View className="svgItems">
|
||||
<View className="svgItem">
|
||||
<View className="bookImg">
|
||||
<Image src={laptop} lazyLoad />
|
||||
<View className="bookImg_text">Tiktok无人直播</View>
|
||||
</View>
|
||||
<View className="bookImg">
|
||||
<Image src={travel} lazyLoad />
|
||||
<View className="bookImg_text">Youtube自媒体</View>
|
||||
</View>
|
||||
<View className="bookImg">
|
||||
<Image src={code} lazyLoad />
|
||||
<View className="bookImg_text">Web: SaaS + Web3</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,316 +1,393 @@
|
||||
.index {
|
||||
// background-color: #002329;
|
||||
// width: 100vw;
|
||||
// padding-top: 80px;
|
||||
height: 100vh;
|
||||
// height: 100%;
|
||||
// padding-left: 100px;
|
||||
// padding-right: 100px;
|
||||
// background-color: yellow;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 30px;
|
||||
background: linear-gradient(180deg, #f8fbff 0%, #fff 100%);
|
||||
|
||||
.index-book {
|
||||
// margin-top: 80px;
|
||||
// width: 100%;
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
// padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
// background-color: #f0f0f0;
|
||||
// background-color: #f0f5ff;
|
||||
// background-color: yellow;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
|
||||
.index_book_left {
|
||||
min-width: 600px;
|
||||
min-height: 300px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
// background-color: rgb(208, 255, 0);
|
||||
justify-content: center;
|
||||
|
||||
.left_title {
|
||||
font-size: 50px;
|
||||
font-weight: 700;
|
||||
color: #69b1ff;
|
||||
font-size: 40px;
|
||||
font-weight: 800;
|
||||
color: #1a1a2e;
|
||||
text-align: center;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.left_text {
|
||||
font-size: 30px;
|
||||
}
|
||||
.left_mobile {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
font-size: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// align-items: center;
|
||||
// justify-content: space-around;
|
||||
// background-color: yellow;
|
||||
|
||||
.left_subtitle {
|
||||
font-size: 26px;
|
||||
color: #8c8c8c;
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-top: 40px;
|
||||
margin-top: 50px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.cardItem {
|
||||
padding: 20px;
|
||||
// padding-top: 20px;
|
||||
width: 500px;
|
||||
// height: 300px;
|
||||
gap: 30px;
|
||||
|
||||
margin-bottom: 20px;
|
||||
.cardItem {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
padding: 28px 34px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: rgb(var(--color-gray-50) / var(--tw-bg-opacity, 1));
|
||||
// background-color: yellow;
|
||||
background-color: #f0f5ff;
|
||||
border-radius: 20px;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
.cardItem_left {
|
||||
// width: 100px;
|
||||
// height: 100%;
|
||||
// background-color: #69b1ff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
margin-right: 40px;
|
||||
margin-right: 30px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.cardItem_left_img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.youtubeSvg {
|
||||
position: relative;
|
||||
top: -5px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.cardItem_right {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// background-color: red;
|
||||
|
||||
.cardItem_rightUp {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
// background-color: aquamarine;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-weight: 700;
|
||||
font-size: 35px;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
font-size: 34px;
|
||||
color: #1a1a2e;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.cardItem_rightDown {
|
||||
width: 100%;
|
||||
// height: 200px;
|
||||
flex: 1;
|
||||
// background-color: red;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
font-size: 30px;
|
||||
flex-wrap: wrap;
|
||||
color: #262626;
|
||||
font-size: 28px;
|
||||
color: #8c8c8c;
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
.left_mobile {
|
||||
margin-top: 20px;
|
||||
// width: 100%;
|
||||
font-size: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// background-color: aqua;
|
||||
// align-items: center;
|
||||
// justify-content: space-around;
|
||||
// background-color: yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left_btn {
|
||||
margin-top: 40px;
|
||||
// background-color: aqua;
|
||||
// display: none;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.startRead {
|
||||
width: 500px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
height: 96px;
|
||||
font-size: 34px;
|
||||
font-weight: 600;
|
||||
border-radius: 48px;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
border: none;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.index_book_img {
|
||||
margin-top: 80px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
margin-bottom: 40px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.book_img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svgItems {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
// background-color: yellow;
|
||||
margin-top: 20px;
|
||||
// padding: 20px;
|
||||
.bookImg {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.index_btn {
|
||||
// background-color: yellow;
|
||||
// margin-top: 40px;
|
||||
.startRead {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
position: absolute;
|
||||
// position: fixed;
|
||||
bottom: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
// margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
// background-color: yellow;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
// ===== Tablet: 768px+ =====
|
||||
@media (min-width: 768PX) {
|
||||
.index {
|
||||
// padding: 100px;
|
||||
height: 90vh;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// background-color: aqua;
|
||||
// color: red;
|
||||
position: relative;
|
||||
padding: 0 40PX;
|
||||
|
||||
.index-book {
|
||||
width: 100%;
|
||||
max-width: 1400px;
|
||||
|
||||
// max-width: 2000px;
|
||||
// padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
// justify-content: center;
|
||||
justify-content: space-between;
|
||||
background-color: #f0f5ff;
|
||||
border-radius: 20px;
|
||||
padding: 40PX 0;
|
||||
|
||||
.index_book_left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
// background-color: yellow;
|
||||
// background-color: #69b1ff;
|
||||
.left_mobile {
|
||||
display: none;
|
||||
.left_title {
|
||||
font-size: 32PX;
|
||||
}
|
||||
|
||||
.left_subtitle {
|
||||
font-size: 16PX;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: none;
|
||||
margin-top: 28PX;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 16PX;
|
||||
|
||||
.cardItem {
|
||||
width: calc(50% - 8PX);
|
||||
max-width: 320PX;
|
||||
padding: 16PX 20PX;
|
||||
|
||||
.cardItem_left {
|
||||
margin-right: 16PX;
|
||||
.cardItem_left_img {
|
||||
width: 48PX;
|
||||
height: 48PX;
|
||||
border-radius: 8PX;
|
||||
}
|
||||
}
|
||||
|
||||
.cardItem_right {
|
||||
.cardItem_rightUp {
|
||||
font-size: 17PX;
|
||||
}
|
||||
.cardItem_rightDown {
|
||||
font-size: 14PX;
|
||||
margin-top: 2PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left_btn {
|
||||
display: flex;
|
||||
margin-top: 28PX;
|
||||
margin-bottom: 28PX;
|
||||
|
||||
.startRead {
|
||||
// display: flex;
|
||||
width: 200px;
|
||||
max-width: 280PX;
|
||||
height: 44PX;
|
||||
font-size: 16PX;
|
||||
border-radius: 22PX;
|
||||
line-height: 44PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
.index_book_img {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// height: 100%;
|
||||
// background-color: yellow;
|
||||
.book_img{
|
||||
margin-bottom: 40px;
|
||||
|
||||
.index_book_img {
|
||||
width: 200PX;
|
||||
height: 200PX;
|
||||
margin-bottom: 20PX;
|
||||
|
||||
.book_img {
|
||||
border-radius: 14PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* stylelint-disable */
|
||||
// ===== Desktop: 1024px+ =====
|
||||
// 使用 PX (大写) 防止 Taro postcss-pxtransform 转换
|
||||
@media (min-width: 1024PX) {
|
||||
.index {
|
||||
justify-content: center;
|
||||
padding: 30PX 80PX 0;
|
||||
|
||||
.index-book {
|
||||
flex-direction: row;
|
||||
max-width: 1200PX;
|
||||
padding: 60PX 50PX;
|
||||
background: #f0f5ff;
|
||||
border-radius: 24PX;
|
||||
gap: 60PX;
|
||||
|
||||
.index_book_left {
|
||||
flex: 1;
|
||||
align-items: flex-start;
|
||||
|
||||
.left_title {
|
||||
font-size: 36PX;
|
||||
text-align: left;
|
||||
line-height: 1.4;
|
||||
letter-spacing: 1PX;
|
||||
}
|
||||
|
||||
.left_subtitle {
|
||||
font-size: 16PX;
|
||||
text-align: left;
|
||||
margin-top: 12PX;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.left_btn {
|
||||
margin-top: 36PX;
|
||||
margin-bottom: 0;
|
||||
max-width: 500PX;
|
||||
justify-content: center;
|
||||
|
||||
.startRead {
|
||||
width: 200PX;
|
||||
max-width: 200PX;
|
||||
height: 48PX;
|
||||
font-size: 16PX;
|
||||
font-weight: 600;
|
||||
border-radius: 24PX;
|
||||
line-height: 48PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.index_book_img {
|
||||
width: 260PX;
|
||||
height: 260PX;
|
||||
margin-bottom: 0;
|
||||
|
||||
.book_img {
|
||||
border-radius: 16PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svgItems {
|
||||
// width: 1400px;
|
||||
width: 100%;
|
||||
max-width: 1400px;
|
||||
margin-top: 80px;
|
||||
// padding: 0px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 1200PX;
|
||||
margin-top: 60PX;
|
||||
margin-bottom: 60PX;
|
||||
justify-content: center;
|
||||
// background-color: #69b1ff;
|
||||
// background-color: yellow;
|
||||
// background-color: brown;
|
||||
|
||||
.svgItem {
|
||||
// min-width: 1400px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
// background-color: #69b1ff;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
gap: 40PX;
|
||||
|
||||
.bookImg {
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
width: 240PX;
|
||||
min-height: 240PX;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// background-color: yellow;
|
||||
padding: 36PX 24PX;
|
||||
background: #fff;
|
||||
border-radius: 16PX;
|
||||
box-shadow: 0 4PX 20PX rgba(0, 0, 0, 0.06);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4PX);
|
||||
box-shadow: 0 8PX 30PX rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.bookImg_text {
|
||||
margin-top: 20px;
|
||||
font-size: 30px;
|
||||
margin-top: 16PX;
|
||||
font-size: 16PX;
|
||||
font-weight: 600;
|
||||
color: #1a1a2e;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.index_btn {
|
||||
.startRead {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
// position: fixed;
|
||||
bottom: 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
// margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
// background-color: yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer_div {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
// ===== Large Desktop: 1536px+ =====
|
||||
@media (min-width: 1536PX) {
|
||||
.index {
|
||||
padding-top: 40PX;
|
||||
|
||||
.index-book {
|
||||
max-width: 1400PX;
|
||||
padding: 80PX 60PX;
|
||||
|
||||
.index_book_left {
|
||||
.left_title {
|
||||
font-size: 42PX;
|
||||
}
|
||||
|
||||
.left_subtitle {
|
||||
font-size: 18PX;
|
||||
}
|
||||
|
||||
.left_btn {
|
||||
max-width: 580PX;
|
||||
|
||||
.startRead {
|
||||
width: 220PX;
|
||||
max-width: 220PX;
|
||||
height: 52PX;
|
||||
font-size: 17PX;
|
||||
border-radius: 26PX;
|
||||
line-height: 52PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.index_book_img {
|
||||
width: 300PX;
|
||||
height: 300PX;
|
||||
}
|
||||
}
|
||||
|
||||
.svgItems {
|
||||
max-width: 1400PX;
|
||||
margin-top: 80PX;
|
||||
|
||||
.svgItem {
|
||||
gap: 50PX;
|
||||
|
||||
.bookImg {
|
||||
width: 300PX;
|
||||
min-height: 300PX;
|
||||
padding: 40PX 30PX;
|
||||
|
||||
.bookImg_text {
|
||||
font-size: 18PX;
|
||||
margin-top: 20PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* stylelint-enable */
|
||||
|
||||
@@ -1,37 +1,158 @@
|
||||
|
||||
// 在 src/index.scss 中引入 GitHub Markdown 主题
|
||||
@import 'github-markdown-css/github-markdown.css';
|
||||
@import "github-markdown-css/github-markdown.css";
|
||||
|
||||
.Sphone {
|
||||
padding: 40px;
|
||||
// font-size: 30px !important;
|
||||
// color: #666;
|
||||
padding: 30px;
|
||||
|
||||
.markdown-body{
|
||||
font-size: 30px !important;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto; /* 保持图像的纵横比 */
|
||||
}
|
||||
.formCode {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.codeBtn {
|
||||
background-color: aquamarine;
|
||||
// height: 80px;
|
||||
// color: red;
|
||||
.markdown-body {
|
||||
font-size: 30px;
|
||||
line-height: 1.8;
|
||||
color: #2c3e50;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
h1 {
|
||||
font-size: 44px;
|
||||
font-weight: 800;
|
||||
color: #1a1a2e;
|
||||
margin: 48px 0 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid #e8e8e8;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 38px;
|
||||
font-weight: 700;
|
||||
color: #2c3e50;
|
||||
margin: 40px 0 20px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 34px;
|
||||
font-weight: 600;
|
||||
color: #34495e;
|
||||
margin: 32px 0 16px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 24px 0;
|
||||
padding: 20px 24px;
|
||||
border-left: 6px solid #4facfe;
|
||||
background: #f8fbff;
|
||||
border-radius: 0 12px 12px 0;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 24px 0;
|
||||
padding: 24px;
|
||||
background: #1e1e2e;
|
||||
border-radius: 12px;
|
||||
overflow-x: auto;
|
||||
|
||||
code {
|
||||
font-family: "SF Mono", "Fira Code", Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 26px;
|
||||
color: #e2e8f0;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.88em;
|
||||
padding: 4px 10px;
|
||||
background: #f1f5f9;
|
||||
color: #e53e3e;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
margin: 24px auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4facfe;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
|
||||
th {
|
||||
background: #f8fafc;
|
||||
font-weight: 600;
|
||||
padding: 16px 20px;
|
||||
border: 1px solid #e2e8f0;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 14px 20px;
|
||||
border: 1px solid #e2e8f0;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background: #f8fafc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.joinSalon {
|
||||
// position: relative;
|
||||
// bottom: 20px;
|
||||
// position: fixed;
|
||||
width: 700px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
border-radius: 12px;
|
||||
font-weight: 600;
|
||||
background-color:#72D572 ;
|
||||
border-color: #72D572 ;;
|
||||
background-color: #72D572;
|
||||
border-color: #72D572;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.Sphone {
|
||||
padding: 30px 60px;
|
||||
|
||||
.markdown-body {
|
||||
font-size: 16px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
|
||||
h1 { font-size: 28px; }
|
||||
h2 { font-size: 24px; }
|
||||
h3 { font-size: 20px; }
|
||||
pre code { font-size: 14px; }
|
||||
table th, table td { font-size: 15px; padding: 10px 16px; }
|
||||
}
|
||||
|
||||
.joinSalon {
|
||||
max-width: 400px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.Sphone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.markdown-body {
|
||||
width: 720px;
|
||||
font-size: 17px;
|
||||
|
||||
pre code { font-size: 14px; }
|
||||
img { max-width: 90%; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user