This commit is contained in:
2026-02-12 20:50:01 +08:00
parent d049f682f5
commit 414d3334fd
82 changed files with 1835 additions and 422 deletions

View File

@@ -1,102 +1,216 @@
.forum-detail-page {
min-height: 100vh;
background-color: #000;
padding-bottom: 80px;
background-color: #121212;
padding-bottom: 90px;
color: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
.topic-card {
background: rgba(20,20,20,0.8);
border-bottom: 1px solid rgba(255,255,255,0.1);
padding: 20px;
margin-bottom: 20px;
background: #1e1e1e;
border-bottom: 1px solid rgba(255,255,255,0.05);
padding: 24px 20px;
margin-bottom: 24px;
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
.header {
margin-bottom: 15px;
margin-bottom: 24px;
.title {
font-size: 20px;
font-weight: bold;
font-size: 32px; /* Increased from 28px */
font-weight: 800;
color: #fff;
margin-bottom: 10px;
margin-bottom: 20px;
line-height: 1.4;
letter-spacing: -0.5px;
}
.meta {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
gap: 12px;
color: #888;
font-size: 12px;
font-size: 14px; /* Increased from 13px */
.author {
display: flex;
align-items: center;
gap: 6px;
gap: 10px;
background: rgba(255,255,255,0.05);
padding: 6px 12px 6px 6px;
border-radius: 20px;
.avatar {
width: 24px;
height: 24px;
width: 32px; /* Larger avatar */
height: 32px;
border-radius: 50%;
border: 1px solid rgba(255,255,255,0.1);
}
.verified {
color: #00b96b;
font-size: 16px;
margin-left: 2px;
}
}
}
}
.content {
font-size: 16px;
line-height: 1.6;
color: #ddd;
font-size: 20px; /* Increased from 18px */
line-height: 1.9; /* Improved readability */
color: #e0e0e0;
letter-spacing: 0.3px;
image {
max-width: 100%;
border-radius: 8px;
margin: 10px 0;
border-radius: 12px;
margin: 24px 0;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
/* Markdown styling enhancements */
h1, h2, h3, h4, h5, h6 { margin-top: 32px; margin-bottom: 20px; color: #fff; font-weight: 700; line-height: 1.4; }
h1 { font-size: 28px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 12px; }
h2 { font-size: 24px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 8px; }
h3 { font-size: 22px; }
h4 { font-size: 20px; }
h5 { font-size: 18px; color: #ddd; }
p { margin-bottom: 24px; }
strong { font-weight: 800; color: #fff; }
em { font-style: italic; color: #aaa; }
del { text-decoration: line-through; color: #666; }
ul, ol { margin-bottom: 24px; padding-left: 20px; }
li { margin-bottom: 8px; list-style-position: outside; }
ul li { list-style-type: disc; }
ol li { list-style-type: decimal; }
/* Task lists */
li input[type="checkbox"] { margin-right: 8px; }
blockquote {
border-left: 4px solid #00b96b;
background: rgba(255, 255, 255, 0.05);
padding: 16px 20px;
margin: 24px 0;
border-radius: 4px;
color: #bbb;
font-size: 18px;
font-style: italic;
p { margin-bottom: 0; }
}
a { color: #00b96b; text-decoration: none; border-bottom: 1px solid transparent; transition: border-color 0.2s; }
hr {
height: 1px;
background: rgba(255,255,255,0.1);
border: none;
margin: 40px 0;
}
table {
width: 100%;
border-collapse: collapse;
margin: 24px 0;
font-size: 16px;
overflow-x: auto;
display: block;
th, td {
border: 1px solid rgba(255,255,255,0.1);
padding: 12px;
text-align: left;
}
th {
background: rgba(255,255,255,0.05);
font-weight: 700;
color: #fff;
}
tr:nth-child(even) {
background: rgba(255,255,255,0.02);
}
}
code {
background: rgba(255,255,255,0.1);
padding: 4px 8px;
border-radius: 4px;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
color: #ff7875;
font-size: 16px;
margin: 0 4px;
}
pre {
background: #161616;
padding: 20px;
border-radius: 12px;
overflow-x: auto;
margin: 24px 0;
border: 1px solid #333;
box-shadow: inset 0 0 20px rgba(0,0,0,0.5);
code {
background: transparent;
color: #a6e22e;
padding: 0;
font-size: 15px;
margin: 0;
white-space: pre;
}
}
}
.media-list {
margin-top: 20px;
margin-top: 24px;
.media-item {
margin-bottom: 15px;
margin-bottom: 16px;
video {
width: 100%;
border-radius: 8px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
}
}
}
.replies-section {
padding: 0 15px;
padding: 0 16px;
.section-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
padding-left: 5px;
border-left: 3px solid #00b96b;
font-size: 18px;
font-weight: 700;
margin-bottom: 20px;
padding-left: 12px;
border-left: 4px solid #00b96b;
color: #fff;
}
.reply-card {
background: rgba(255,255,255,0.05);
border-radius: 8px;
padding: 15px;
margin-bottom: 15px;
background: #1e1e1e;
border-radius: 12px;
padding: 24px; /* Increased padding */
margin-bottom: 24px;
display: flex;
gap: 10px;
gap: 16px; /* Increased gap */
border: 1px solid rgba(255,255,255,0.03);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
.avatar {
width: 30px;
height: 30px;
width: 44px; /* Larger avatar */
height: 44px;
border-radius: 50%;
flex-shrink: 0;
border: 1px solid rgba(255,255,255,0.1);
}
.reply-main {
@@ -105,29 +219,33 @@
.reply-header {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
align-items: baseline;
margin-bottom: 12px;
.nickname {
font-weight: bold;
color: #aaa;
font-size: 14px;
font-weight: 600;
color: #ddd;
font-size: 16px; /* Larger nickname */
}
.time {
color: #666;
font-size: 12px;
font-size: 13px;
background: rgba(255,255,255,0.05);
padding: 3px 8px;
border-radius: 4px;
}
}
.reply-content {
font-size: 14px;
color: #eee;
line-height: 1.5;
font-size: 17px; /* Larger reply text */
color: #ccc;
line-height: 1.8;
image {
max-width: 100%;
border-radius: 4px;
margin-top: 5px;
border-radius: 8px;
margin-top: 14px;
}
}
}
@@ -139,36 +257,57 @@
bottom: 0;
left: 0;
right: 0;
background: #1a1a1a;
padding: 10px 15px;
border-top: 1px solid #333;
background: rgba(20, 20, 20, 0.95); /* More opaque */
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
padding: 16px 20px;
padding-bottom: calc(16px + env(safe-area-inset-bottom));
border-top: 1px solid rgba(255,255,255,0.1);
display: flex;
align-items: center;
gap: 10px;
gap: 16px;
z-index: 100;
box-shadow: 0 -4px 20px rgba(0,0,0,0.3);
.input-wrapper {
flex: 1;
background: #333;
border-radius: 20px;
padding: 8px 15px;
input {
color: #fff;
width: 100%;
}
flex: 1;
background: rgba(255,255,255,0.1);
border-radius: 26px;
padding: 14px 20px; /* Larger input area */
transition: all 0.3s;
border: 1px solid transparent;
&:focus-within {
background: rgba(255,255,255,0.15);
border-color: rgba(0, 185, 107, 0.5);
}
input {
color: #fff;
width: 100%;
font-size: 18px; /* Larger text */
}
}
.action-btn {
padding: 0 10px;
width: 48px; /* Larger touch target */
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background 0.2s;
&:active {
background: rgba(255,255,255,0.1);
}
}
.send-btn {
color: #00b96b;
font-weight: bold;
font-weight: 700;
font-size: 16px;
padding: 0 8px;
}
}
}

View File

@@ -20,11 +20,12 @@ const ForumDetail = () => {
const fetchDetail = async () => {
try {
const res = await getTopicDetail(Number(id))
setTopic(res.data)
const topicData = res.data || res
setTopic(topicData)
// Parse markdown
if (res.data.content) {
const html = marked.parse(res.data.content)
if (topicData.content) {
const html = marked.parse(topicData.content)
// Basic fix for images to fit screen
const styledHtml = (html as string).replace(/<img/g, '<img style="max-width:100%;border-radius:8px;"')
setHtmlContent(styledHtml)
@@ -87,7 +88,7 @@ const ForumDetail = () => {
let url = uploadRes.file
// Ensure full URL if needed (backend usually returns relative or absolute)
if (url && !url.startsWith('http')) {
const BASE_URL = process.env.TARO_APP_API_URL || 'https://market.quant-speed.com/api'
const BASE_URL = (typeof process !== 'undefined' && process.env && process.env.TARO_APP_API_URL) || 'https://market.quant-speed.com/api'
const host = BASE_URL.replace(/\/api\/?$/, '')
if (!url.startsWith('/')) url = '/' + url
url = `${host}${url}`
@@ -149,23 +150,26 @@ const ForumDetail = () => {
<Text className='title'>{topic.title}</Text>
<View className='meta'>
<View className='author'>
<Image className='avatar' src={topic.author_info?.avatar_url || 'https://via.placeholder.com/30'} />
<Text>{topic.author_info?.nickname}</Text>
{topic.is_verified_owner && <Text className='verified'></Text>}
</View>
<Text></Text>
<Text>{new Date(topic.created_at).toLocaleDateString()}</Text>
<Text></Text>
<Text>{topic.view_count} </Text>
{userInfo && topic.author === userInfo.id && (
<View onClick={handleEdit} style={{display: 'flex', alignItems: 'center', marginLeft: 'auto', padding: '4px 8px', background: 'rgba(255,255,255,0.1)', borderRadius: 4}}>
<AtIcon value='edit' size='14' color='#00b96b' />
<Text style={{fontSize: 12, color: '#00b96b', marginLeft: 4}}></Text>
<View className='author'>
<Image className='avatar' src={topic.author_info?.avatar_url || 'https://via.placeholder.com/30'} />
<Text style={{fontWeight: 600, color: '#ccc'}}>{topic.author_info?.nickname}</Text>
{topic.is_verified_owner && <AtIcon value='check-circle' size='14' color='#00b96b' />}
</View>
)}
</View>
<Text></Text>
<Text>{new Date(topic.created_at).toLocaleDateString()}</Text>
<Text></Text>
<View style={{display: 'flex', alignItems: 'center'}}>
<AtIcon value='eye' size='14' color='#666' style={{marginRight: 4}} />
<Text>{topic.view_count}</Text>
</View>
{userInfo && topic.author === userInfo.id && (
<View onClick={handleEdit} style={{display: 'flex', alignItems: 'center', marginLeft: 'auto', padding: '6px 12px', background: 'rgba(0, 185, 107, 0.15)', borderRadius: 20}}>
<AtIcon value='edit' size='14' color='#00b96b' />
<Text style={{fontSize: 12, color: '#00b96b', marginLeft: 4, fontWeight: 600}}></Text>
</View>
)}
</View>
</View>
<View className='content'>
@@ -191,8 +195,11 @@ const ForumDetail = () => {
<Image className='avatar' src={reply.author_info?.avatar_url || 'https://via.placeholder.com/30'} />
<View className='reply-main'>
<View className='reply-header'>
<Text className='nickname'>{reply.author_info?.nickname}</Text>
<Text className='time'>#{idx + 1} {new Date(reply.created_at).toLocaleDateString()}</Text>
<View style={{display: 'flex', flexDirection: 'column'}}>
<Text className='nickname'>{reply.author_info?.nickname}</Text>
<Text style={{fontSize: 10, color: '#666', marginTop: 2}}>#{idx + 1} {new Date(reply.created_at).toLocaleDateString()}</Text>
</View>
<AtIcon value='message' size='14' color='#444' />
</View>
<View className='reply-content'>
{/* Simple markdown render for replies or just text if complex */}