feat: Add user likes tab and local timeline, update branding assets

- Add likes tab to user profiles displaying user's liked posts
- Implement new `/api/users/[handle]/likes` endpoint to fetch user's liked posts
- Add local timeline feed type to show only local node posts without fediverse content
- Update favicon and add new logotext branding asset
- Enhance search results with isLiked and isReposted status for authenticated users
- Populate like and repost information in search posts endpoint
- Update profile page tabs to conditionally show likes tab for non-bot users
- Add loading states and empty state messaging for likes tab
- Remove deprecated guide page
- Improve bot settings page and content generation logic
This commit is contained in:
AskIt
2026-01-25 19:45:34 +01:00
parent 465bd8b60c
commit d36c1c93e5
14 changed files with 509 additions and 289 deletions
+40 -2
View File
@@ -81,13 +81,15 @@ export default function ProfilePage() {
const [user, setUser] = useState<User | null>(null);
const [posts, setPosts] = useState<Post[]>([]);
const [likedPosts, setLikedPosts] = useState<Post[]>([]);
const [currentUser, setCurrentUser] = useState<{ id: string; handle: string } | null>(null);
const [isFollowing, setIsFollowing] = useState(false);
const [loading, setLoading] = useState(true);
const [activeTab, setActiveTab] = useState<'posts' | 'followers' | 'following'>('posts');
const [activeTab, setActiveTab] = useState<'posts' | 'likes' | 'followers' | 'following'>('posts');
const [followers, setFollowers] = useState<UserSummary[]>([]);
const [following, setFollowing] = useState<UserSummary[]>([]);
const [postsLoading, setPostsLoading] = useState(true);
const [likesLoading, setLikesLoading] = useState(false);
const [followersLoading, setFollowersLoading] = useState(false);
const [followingLoading, setFollowingLoading] = useState(false);
const [isEditing, setIsEditing] = useState(false);
@@ -106,6 +108,7 @@ export default function ProfilePage() {
setSaveError(null);
setFollowers([]);
setFollowing([]);
setLikedPosts([]);
// Get current user
fetch('/api/auth/me')
.then(res => res.json())
@@ -197,6 +200,15 @@ export default function ProfilePage() {
.catch(() => setFollowing([]))
.finally(() => setFollowingLoading(false));
}
if (activeTab === 'likes') {
setLikesLoading(true);
fetch(`/api/users/${handle}/likes`)
.then(res => res.json())
.then(data => setLikedPosts(data.posts || []))
.catch(() => setLikedPosts([]))
.finally(() => setLikesLoading(false));
}
}, [activeTab, handle]);
const handleFollow = async () => {
@@ -617,7 +629,10 @@ export default function ProfilePage() {
{/* Tabs */}
<div style={{ display: 'flex', borderTop: '1px solid var(--border)' }}>
{(['posts', 'followers', 'following'] as const).map(tab => (
{(user?.isBot
? ['posts', 'followers', 'following'] as const
: ['posts', 'likes', 'followers', 'following'] as const
).map(tab => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
@@ -663,6 +678,29 @@ export default function ProfilePage() {
)
)}
{activeTab === 'likes' && (
likesLoading ? (
<div style={{ padding: '48px', textAlign: 'center', color: 'var(--foreground-tertiary)' }}>
<p>Loading...</p>
</div>
) : likedPosts.length === 0 ? (
<div style={{ padding: '48px', textAlign: 'center', color: 'var(--foreground-tertiary)' }}>
<p>No liked posts yet</p>
</div>
) : (
likedPosts.map((post, index) => (
<PostCard
key={`${post.id}-${index}`}
post={post}
onLike={handleLike}
onRepost={handleRepost}
onComment={handleComment}
onDelete={handleDelete}
/>
))
)
)}
{activeTab === 'followers' && (
followersLoading ? (
<div style={{ padding: '24px', textAlign: 'center', color: 'var(--foreground-tertiary)' }}>