diff --git a/.kilo/package-lock.json b/.kilo/package-lock.json
new file mode 100644
index 0000000..86ea34f
--- /dev/null
+++ b/.kilo/package-lock.json
@@ -0,0 +1,115 @@
+{
+ "name": ".kilo",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "@kilocode/plugin": "7.2.10"
+ }
+ },
+ "node_modules/@kilocode/plugin": {
+ "version": "7.2.10",
+ "resolved": "https://registry.npmjs.org/@kilocode/plugin/-/plugin-7.2.10.tgz",
+ "integrity": "sha512-VJPhJC+E5WWu7XgEJzrVOxKJlwJ+OATwxEzgjqEPj8KN5N38YxUPBY/rzUTjv90x7nkzyk1rFGfCVqXdA/Koug==",
+ "license": "MIT",
+ "dependencies": {
+ "@kilocode/sdk": "7.2.10",
+ "zod": "4.1.8"
+ },
+ "peerDependencies": {
+ "@opentui/core": ">=0.1.97",
+ "@opentui/solid": ">=0.1.97"
+ },
+ "peerDependenciesMeta": {
+ "@opentui/core": {
+ "optional": true
+ },
+ "@opentui/solid": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@kilocode/sdk": {
+ "version": "7.2.10",
+ "resolved": "https://registry.npmjs.org/@kilocode/sdk/-/sdk-7.2.10.tgz",
+ "integrity": "sha512-H6jGXYAhN/yjOGX3MRZ0OxyEAuRGY3VOwDbLTh4O6ljpgutFHaLvomDZ82qNVy7gl7AjJgi3SAQAt9UQpeGl/w==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "7.0.6"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/zod": {
+ "version": "4.1.8",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ }
+ }
+}
diff --git a/src/screens/home/PostDetailScreen.tsx b/src/screens/home/PostDetailScreen.tsx
index ded82b6..4919fae 100644
--- a/src/screens/home/PostDetailScreen.tsx
+++ b/src/screens/home/PostDetailScreen.tsx
@@ -22,7 +22,7 @@ import {
Image,
Clipboard,
} from 'react-native';
-import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useNavigation, useRouter, useLocalSearchParams } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import * as ImagePicker from 'expo-image-picker';
@@ -795,8 +795,9 @@ export const PostDetailScreen: React.FC = () => {
}
setCommentText('');
- setCommentImages([]); // 清除图片
- setReplyingTo(null); // 清除回复状态
+ setCommentImages([]);
+ setReplyingTo(null);
+ setIsComposerVisible(false);
// 更新帖子评论数
setPost(prev => prev ? {
@@ -1235,74 +1236,35 @@ export const PostDetailScreen: React.FC = () => {
)}
- {/* 底部操作栏 - QQ频道风格 */}
-
-
-
-
- {post.likes_count > 0 ? formatNumber(post.likes_count) : '点赞'}
+ {/* 评论标题 - 类似图片中的样式 */}
+
+
+
+ 评论
-
-
-
-
-
- {post.comments_count > 0 ? formatNumber(post.comments_count) : '评论'}
+
+ {post.comments_count || 0}
-
-
-
-
-
- {post.shares_count > 0 ? formatNumber(post.shares_count) : '分享'}
-
-
-
-
-
-
- {post.is_favorited ? '已收藏' : '收藏'}
-
-
-
-
- {/* 评论标题 - 现代化简洁分区头 */}
-
-
-
-
- 评论区
-
-
- {post.comments_count}
-
-
+
);
- }, [post, postImages, currentUser?.id, isDeleting, handleLike, handleShare, handleFavorite, handleDeletePost, handleEditPost, handleImagePress, voteResult, isVoteLoading, handleVote, handleUnvote, isDesktop, isTablet, isWideScreen, responsivePadding, responsiveGap]);
+ }, [post, postImages, currentUser?.id, isDeleting, handleDeletePost, handleEditPost, handleImagePress, voteResult, isVoteLoading, handleVote, handleUnvote, isDesktop, isTablet, isWideScreen, responsivePadding, responsiveGap]);
// 回复评论
const [replyingTo, setReplyingTo] = useState(null);
+ const [isComposerVisible, setIsComposerVisible] = useState(false);
const handleReply = (comment: Comment) => {
setReplyingTo(comment);
- // 可以在这里添加聚焦输入框的逻辑
+ setIsComposerVisible(true);
};
const handleCancelReply = () => {
@@ -1373,37 +1335,42 @@ export const PostDetailScreen: React.FC = () => {
);
}, [currentUser?.id, handleDeleteComment, handleImagePress, handleLikeComment, handleLoadMoreReplies, post?.user_id, handleReportComment]);
- // 渲染空评论 - 现代化设计
+ // 渲染空评论 - 类似图片中的样式
const renderEmptyComments = useCallback(() => (
-
-
+ {/* 四个方块图标 */}
+
+
+
+
+
-
- 还没有评论
-
-
- 成为第一个评论的人吧~
+
+ 这里空空如也,邀请好友来互动吧!
- ), [isDesktop]);
+ ), []);
+
+ const openComposer = () => {
+ setIsComposerVisible(true);
+ };
+
+ const closeComposer = () => {
+ setIsComposerVisible(false);
+ Keyboard.dismiss();
+ };
- // 渲染评论输入框
const renderCommentInput = () => (
{/* 回复提示 */}
- {replyingTo && (
+ {replyingTo && !isComposerVisible && (
回复 {replyingTo.author.nickname}
@@ -1413,70 +1380,153 @@ export const PostDetailScreen: React.FC = () => {
)}
-
- {/* 已选图片预览 */}
- {commentImages.length > 0 && (
-
- {commentImages.map((image, index) => (
-
-
- {image.uploading && (
-
-
-
- )}
- handleRemoveCommentImage(index)}
- >
-
+
+ {!isComposerVisible ? (
+ /* Collapsed state - simple input trigger */
+
+
+
+ {replyingTo ? `回复 ${replyingTo.author.nickname}...` : '来说点什么吧!'}
+
+
+
+
+
+
+ {formatNumber(post?.likes_count || 0)}
+
+
+
+
+
+
+ {formatNumber(post?.favorites_count || 0)}
+
+
+
+
+
+
+ {formatNumber(post?.shares_count || 0)}
+
+
+
+ ) : (
+ /* Expanded state - full composer */
+
+ {/* Reply hint */}
+ {replyingTo && (
+
+
+ 回复 {replyingTo.author.nickname}
+
+
+
- ))}
-
+ )}
+
+ {/* Text Input */}
+
+
+ {/* Image preview */}
+ {commentImages.length > 0 && (
+
+ {commentImages.map((image, index) => (
+
+
+ {image.uploading && (
+
+
+
+ )}
+ handleRemoveCommentImage(index)}
+ >
+
+
+
+ ))}
+
+ )}
+
+ {/* Toolbar */}
+
+
+ = 3}
+ >
+ = 3 ? colors.text.disabled : colors.text.secondary}
+ />
+
+ {}}
+ >
+
+
+ {}}
+ >
+
+
+
+ {commentText.length}/500
+
+
+
+ 0) && styles.expandedSendButtonDisabled
+ ]}
+ onPress={handleSendComment}
+ disabled={!(commentText.trim() || commentImages.length > 0)}
+ >
+ 发送
+
+
+
)}
-
-
- {/* 图片选择按钮 */}
- = 3}
- >
- = 3 ? colors.text.disabled : colors.text.secondary}
- />
-
-
-
- 0) && styles.sendButtonDisabled
- ]}
- onPress={handleSendComment}
- disabled={!(commentText.trim() || commentImages.length > 0)}
- >
- 0) ? colors.primary.main : colors.text.disabled}
- />
-
-
);
@@ -1559,20 +1609,20 @@ export const PostDetailScreen: React.FC = () => {
if (!post) {
return (
-
+
-
+
);
}
// 桌面端双栏布局
if (useDualColumnLayout) {
return (
-
+
{
onClose={() => setShowImageModal(false)}
enableSave
/>
-
+
);
}
// 移动端单栏布局
return (
-
+
{
setReportTarget(null);
}}
/>
-
+
);
};
@@ -1915,62 +1965,35 @@ function createPostDetailStyles(colors: AppColors) {
voteLoadingText: {
marginTop: spacing.sm,
},
- actionBar: {
- flexDirection: 'row',
- justifyContent: 'space-around',
- paddingVertical: spacing.md,
- borderTopWidth: StyleSheet.hairlineWidth,
- borderTopColor: colors.divider,
- backgroundColor: colors.background.paper,
- },
- actionButton: {
- flexDirection: 'row',
- alignItems: 'center',
- paddingHorizontal: spacing.md,
- paddingVertical: spacing.xs,
- borderRadius: borderRadius.lg,
- },
- actionText: {
- fontSize: fontSizes.sm,
- marginLeft: 6,
- fontWeight: '500',
- },
commentSectionHeader: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between',
- borderTopWidth: StyleSheet.hairlineWidth,
- borderTopColor: colors.divider,
+ flexDirection: 'column',
+ alignItems: 'flex-start',
paddingTop: spacing.lg,
},
- commentSectionTitleBlock: {
- flex: 1,
- minWidth: 0,
- },
commentSectionTitleRow: {
flexDirection: 'row',
alignItems: 'center',
},
commentSectionTitle: {
- fontWeight: '800',
+ fontWeight: '600',
color: colors.text.primary,
- letterSpacing: -0.2,
+ letterSpacing: 0,
},
- commentCountBadge: {
- backgroundColor: colors.background.default,
- borderWidth: StyleSheet.hairlineWidth,
- borderColor: colors.divider,
- paddingHorizontal: spacing.sm + 2,
- paddingVertical: 3,
- borderRadius: 999,
- marginLeft: spacing.sm,
- minWidth: 24,
- alignItems: 'center',
+ commentSectionCount: {
+ marginLeft: spacing.xs,
+ fontSize: fontSizes.sm,
},
- commentCountText: {
- fontSize: fontSizes.xs,
- fontWeight: '700',
- color: colors.text.secondary,
+ commentSectionUnderline: {
+ width: 28,
+ height: 3,
+ backgroundColor: colors.text.primary,
+ marginTop: spacing.xs,
+ borderRadius: borderRadius.xs,
+ },
+ commentSectionCount: {
+ marginLeft: spacing.xs,
+ fontSize: fontSizes.sm,
+ color: colors.text.hint,
},
inputContainer: {
backgroundColor: colors.background.paper,
@@ -1991,29 +2014,37 @@ function createPostDetailStyles(colors: AppColors) {
marginLeft: spacing.sm,
padding: 2,
},
- inputWrapper: {
+ inputTrigger: {
+ flex: 1,
+ backgroundColor: colors.background.default,
+ borderRadius: 18,
+ paddingHorizontal: spacing.md,
+ paddingVertical: spacing.sm + 2,
+ minHeight: 38,
+ justifyContent: 'center',
+ },
+ inputTriggerText: {
+ fontSize: fontSizes.sm,
+ color: colors.text.hint,
+ },
+ bottomComposerRow: {
flexDirection: 'row',
alignItems: 'center',
- backgroundColor: colors.background.default,
- borderRadius: 20,
- paddingHorizontal: spacing.md,
+ gap: spacing.xs + 2,
},
- input: {
- flex: 1,
- minHeight: 40,
- maxHeight: 100,
- color: colors.text.primary,
- paddingVertical: spacing.sm,
+ bottomActionItem: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingVertical: 2,
+ paddingHorizontal: spacing.sm + 1,
+ marginLeft: spacing.xs,
},
- sendButton: {
- padding: spacing.sm,
- },
- sendButtonDisabled: {
- opacity: 0.5,
- },
- imagePickerButton: {
- padding: spacing.sm,
- marginRight: spacing.xs,
+ bottomActionCount: {
+ marginTop: 1,
+ fontSize: fontSizes.xs,
+ color: colors.text.secondary,
+ lineHeight: fontSizes.xs + 2,
+ fontWeight: '500',
},
commentImagesPreview: {
maxHeight: 80,
@@ -2050,6 +2081,62 @@ function createPostDetailStyles(colors: AppColors) {
backgroundColor: colors.background.paper,
borderRadius: 9,
},
+ // Expanded composer styles
+ expandedComposer: {
+ backgroundColor: colors.background.paper,
+ },
+ expandedReplyHint: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginBottom: spacing.sm,
+ },
+ expandedTextInput: {
+ minHeight: 80,
+ maxHeight: 160,
+ fontSize: fontSizes.md,
+ color: colors.text.primary,
+ paddingVertical: spacing.sm,
+ textAlignVertical: 'top',
+ lineHeight: 22,
+ },
+ expandedToolbar: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginTop: spacing.sm,
+ paddingTop: spacing.sm,
+ borderTopWidth: StyleSheet.hairlineWidth,
+ borderTopColor: colors.divider,
+ },
+ expandedToolbarLeft: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ flex: 1,
+ },
+ expandedToolbarItem: {
+ padding: spacing.xs,
+ marginRight: spacing.sm,
+ },
+ expandedCharCount: {
+ marginLeft: 'auto',
+ marginRight: spacing.sm,
+ },
+ expandedSendButton: {
+ backgroundColor: colors.primary.main,
+ paddingHorizontal: spacing.md,
+ paddingVertical: spacing.sm,
+ borderRadius: borderRadius.md,
+ minWidth: 60,
+ alignItems: 'center',
+ },
+ expandedSendButtonDisabled: {
+ backgroundColor: colors.text.disabled,
+ },
+ expandedSendButtonText: {
+ color: colors.text.inverse,
+ fontSize: fontSizes.sm,
+ fontWeight: '600',
+ },
modalContainer: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.9)',
@@ -2074,33 +2161,33 @@ function createPostDetailStyles(colors: AppColors) {
paddingVertical: spacing.xs,
borderRadius: borderRadius.md,
},
- // 空评论状态样式(与平铺评论区一致,无卡片气泡)
+ // 空评论状态样式(类似图片中的四个方块样式)
emptyCommentsContainer: {
alignItems: 'center',
justifyContent: 'center',
- marginHorizontal: spacing.md,
- marginTop: spacing.md,
- marginBottom: spacing.lg,
- paddingVertical: spacing.xl,
- paddingHorizontal: spacing.md,
+ paddingVertical: spacing.xl * 2.5,
},
- emptyCommentsIconWrapper: {
- width: 40,
- height: 40,
- alignItems: 'center',
- justifyContent: 'center',
- marginBottom: spacing.sm,
- opacity: 0.85,
+ emptyCommentsGrid: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ width: 48,
+ height: 48,
+ marginBottom: spacing.md,
},
- emptyCommentsTitle: {
- fontSize: fontSizes.md,
- fontWeight: '500',
- color: colors.text.primary,
- marginBottom: spacing.xs,
+ emptyCommentsGridItem: {
+ width: 20,
+ height: 20,
+ backgroundColor: colors.background.disabled,
+ margin: 2,
+ borderRadius: borderRadius.xs,
+ },
+ emptyCommentsGridItemActive: {
+ backgroundColor: colors.text.hint,
},
emptyCommentsSubtitle: {
fontSize: fontSizes.sm,
textAlign: 'center',
+ color: colors.text.hint,
},
// 侧边栏样式
sidebar: {