From 3818a250605d6256ab64ce90a0cb2339838a1bec Mon Sep 17 00:00:00 2001 From: sirpiglr <49359077-sirpiglr@users.noreply.replit.com> Date: Mon, 8 Dec 2025 23:52:41 +0000 Subject: [PATCH] Update UI to align with Discord's design language and improve layout Refactors the Activity page to use Discord's color palette, spacing grid, and component styling, including a more compact header and tab bar, layered cards, and thicker progress bars. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9203795e-937a-4306-b81d-b4d5c78c240e Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: c33a91bf-2af4-4f4b-b054-7833453868a3 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7c94b7a0-29c7-4f2e-94ef-44b2153872b7/9203795e-937a-4306-b81d-b4d5c78c240e/LFvmEVc Replit-Helium-Checkpoint-Created: true --- .replit | 4 + client/pages/Activity.tsx | 715 +++++++++++++------------------------- 2 files changed, 241 insertions(+), 478 deletions(-) diff --git a/.replit b/.replit index d96c59f0..2bc87f1a 100644 --- a/.replit +++ b/.replit @@ -47,6 +47,10 @@ externalPort = 3003 localPort = 8080 externalPort = 8080 +[[ports]] +localPort = 36709 +externalPort = 4200 + [[ports]] localPort = 38557 externalPort = 3000 diff --git a/client/pages/Activity.tsx b/client/pages/Activity.tsx index 47ba5838..ced0695e 100644 --- a/client/pages/Activity.tsx +++ b/client/pages/Activity.tsx @@ -1,12 +1,6 @@ import { useEffect, useState, useCallback } from "react"; import { useDiscordActivity } from "@/contexts/DiscordActivityContext"; import LoadingScreen from "@/components/LoadingScreen"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; -import { Progress } from "@/components/ui/progress"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { ScrollArea } from "@/components/ui/scroll-area"; import { Heart, MessageCircle, @@ -27,20 +21,21 @@ import { CheckCircle, AlertCircle, Loader2, + ChevronRight, } from "lucide-react"; const APP_URL = "https://aethex.dev"; type ArmType = "labs" | "gameforge" | "corp" | "foundation" | "devlink" | "nexus" | "staff"; -const ARM_CONFIG: Record = { - labs: { label: "Labs", icon: Zap, color: "text-yellow-400", bgClass: "bg-yellow-500/20", borderClass: "border-yellow-500" }, - gameforge: { label: "GameForge", icon: Gamepad2, color: "text-green-400", bgClass: "bg-green-500/20", borderClass: "border-green-500" }, - corp: { label: "Corp", icon: Briefcase, color: "text-blue-400", bgClass: "bg-blue-500/20", borderClass: "border-blue-500" }, - foundation: { label: "Foundation", icon: BookOpen, color: "text-red-400", bgClass: "bg-red-500/20", borderClass: "border-red-500" }, - devlink: { label: "Dev-Link", icon: Network, color: "text-cyan-400", bgClass: "bg-cyan-500/20", borderClass: "border-cyan-500" }, - nexus: { label: "Nexus", icon: Sparkles, color: "text-purple-400", bgClass: "bg-purple-500/20", borderClass: "border-purple-500" }, - staff: { label: "Staff", icon: Shield, color: "text-indigo-400", bgClass: "bg-indigo-500/20", borderClass: "border-indigo-500" }, +const ARM_CONFIG: Record = { + labs: { label: "Labs", icon: Zap, color: "#facc15", accent: "bg-yellow-500" }, + gameforge: { label: "GameForge", icon: Gamepad2, color: "#4ade80", accent: "bg-green-500" }, + corp: { label: "Corp", icon: Briefcase, color: "#60a5fa", accent: "bg-blue-500" }, + foundation: { label: "Foundation", icon: BookOpen, color: "#f87171", accent: "bg-red-500" }, + devlink: { label: "Dev-Link", icon: Network, color: "#22d3ee", accent: "bg-cyan-500" }, + nexus: { label: "Nexus", icon: Sparkles, color: "#c084fc", accent: "bg-purple-500" }, + staff: { label: "Staff", icon: Shield, color: "#818cf8", accent: "bg-indigo-500" }, }; interface Post { @@ -53,22 +48,7 @@ interface Post { likes_count: number; comments_count: number; tags?: string[]; - user_profiles?: { - id: string; - username?: string; - full_name?: string; - avatar_url?: string; - }; -} - -interface Opportunity { - id: string; - title: string; - description: string; - job_type: string; - arm_affiliation: ArmType; - salary_min?: number; - salary_max?: number; + user_profiles?: { id: string; username?: string; full_name?: string; avatar_url?: string }; } interface Quest { @@ -97,262 +77,138 @@ interface LeaderboardEntry { rank: number; user_id: string; username: string; - avatar_url?: string; xp: number; level: number; streak?: number; } -function ErrorMessage({ message, onRetry }: { message: string; onRetry?: () => void }) { - return ( -
- -

{message}

- {onRetry && ( - - )} -
- ); -} - -function LoadingSpinner() { - return ( -
- -
- ); -} - function FeedTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [needsAuth, setNeedsAuth] = useState(false); const fetchPosts = useCallback(async () => { setLoading(true); setError(null); - setNeedsAuth(false); try { - const response = await fetch("/api/feed?limit=10"); - if (response.status === 401 || response.status === 403) { - setNeedsAuth(true); - return; - } - if (!response.ok) { - const errorData = await response.json().catch(() => ({})); - throw new Error(errorData.error || `Failed to fetch posts (${response.status})`); - } + const response = await fetch("/api/feed?limit=8"); + if (!response.ok) throw new Error("Failed to load"); const data = await response.json(); - setPosts(data.posts || []); - } catch (err: any) { - console.error("[Activity Feed] Error:", err); - setError(err.message || "Failed to load feed"); + setPosts(data.data || []); + } catch { + setError("Couldn't load feed"); } finally { setLoading(false); } }, []); - useEffect(() => { - fetchPosts(); - }, [fetchPosts]); + useEffect(() => { fetchPosts(); }, [fetchPosts]); - if (loading) return ; - if (needsAuth) { - return ( -
-

Sign in on the web to view the community feed

- -
- ); - } - if (error) return ; - - return ( - -
- {posts.length === 0 ? ( -
-

No posts yet. Be the first to share!

- -
- ) : ( - posts.map((post) => { - const config = ARM_CONFIG[post.arm_affiliation] || ARM_CONFIG.labs; - const Icon = config.icon; - return ( - - -
- {post.user_profiles?.avatar_url && ( - - )} -
-
- - {post.user_profiles?.full_name || post.user_profiles?.username || "Anonymous"} - - - - {config.label} - -
-

{post.title}

-

{post.content}

-
- - - {post.likes_count || 0} - - - - {post.comments_count || 0} - - -
-
-
-
-
- ); - }) - )} - {posts.length > 0 && ( - - )} -
-
+ if (loading) return
; + if (error) return ( +
+

{error}

+ +
); -} - -function RealmSwitcher({ - currentRealm, - openExternalLink, -}: { - currentRealm: ArmType; - openExternalLink: (url: string) => Promise; -}) { - const realms = Object.entries(ARM_CONFIG) as [ArmType, typeof ARM_CONFIG.labs][]; return ( -
-
-

Your Realms

-

Explore the different realms of AeThex

-
- -
-

- Your current realm: {ARM_CONFIG[currentRealm]?.label || "Labs"} -

-
- -
- {realms.map(([key, config]) => { - const Icon = config.icon; - const isActive = currentRealm === key; +
+ {posts.length === 0 ? ( + + ) : ( + posts.map((post) => { + const config = ARM_CONFIG[post.arm_affiliation] || ARM_CONFIG.labs; return ( - ); - })} -
- - + }) + )} +
); } -function AchievementsTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { - const achievements: Achievement[] = [ - { id: "1", name: "First Post", description: "Create your first community post", icon: "πŸ“", xp_reward: 50, unlocked: true }, - { id: "2", name: "Social Butterfly", description: "Follow 5 different realms", icon: "πŸ¦‹", xp_reward: 100, unlocked: true }, - { id: "3", name: "Realm Explorer", description: "Visit all 7 realms", icon: "πŸ—ΊοΈ", xp_reward: 150, unlocked: false, progress: 5, total: 7 }, - { id: "4", name: "Community Leader", description: "Get 100 likes on your posts", icon: "πŸ‘‘", xp_reward: 500, unlocked: false, progress: 42, total: 100 }, - { id: "5", name: "Mentor", description: "Complete 10 mentorship sessions", icon: "πŸŽ“", xp_reward: 300, unlocked: false, progress: 3, total: 10 }, - { id: "6", name: "Hot Streak", description: "Log in 7 days in a row", icon: "πŸ”₯", xp_reward: 200, unlocked: false, progress: 4, total: 7 }, - ]; - - const unlockedCount = achievements.filter((a) => a.unlocked).length; - +function RealmsTab({ currentRealm, openExternalLink }: { currentRealm: ArmType; openExternalLink: (url: string) => Promise }) { + const realms = Object.entries(ARM_CONFIG) as [ArmType, typeof ARM_CONFIG[ArmType]][]; + return ( - -
-
-
- - {unlockedCount}/{achievements.length} Unlocked -
- Preview -
- - {achievements.slice(0, 5).map((achievement) => ( -
-
- {achievement.icon} -
-
-
-

{achievement.name}

- {achievement.unlocked && } -
- +{achievement.xp_reward} -
-

{achievement.description}

-
-
- {!achievement.unlocked && achievement.progress !== undefined && ( -
-
- - {achievement.progress}/{achievement.total} -
-
- )} -
- ))} - +
+
+ {realms.map(([key, config]) => { + const Icon = config.icon; + const isActive = currentRealm === key; + return ( + + ); + })}
- + +
); } -function LeaderboardTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { +function BadgesTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { + const achievements: Achievement[] = [ + { id: "1", name: "First Post", description: "Create your first post", icon: "πŸ“", xp_reward: 50, unlocked: true }, + { id: "2", name: "Social Butterfly", description: "Follow 5 realms", icon: "πŸ¦‹", xp_reward: 100, unlocked: true }, + { id: "3", name: "Realm Explorer", description: "Visit all 7 realms", icon: "πŸ—ΊοΈ", xp_reward: 150, unlocked: false, progress: 5, total: 7 }, + { id: "4", name: "Community Leader", description: "Get 100 likes", icon: "πŸ‘‘", xp_reward: 500, unlocked: false, progress: 42, total: 100 }, + ]; + + return ( +
+ {achievements.map((a) => ( +
+ {a.icon} +
+
+ {a.name} + +{a.xp_reward} XP +
+

{a.description}

+ {!a.unlocked && a.progress !== undefined && ( +
+
+
+
+ {a.progress}/{a.total} +
+ )} +
+ {a.unlocked && } +
+ ))} + +
+ ); +} + +function TopTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { const leaderboard: LeaderboardEntry[] = [ { rank: 1, user_id: "1", username: "CodeMaster", xp: 12500, level: 25, streak: 14 }, { rank: 2, user_id: "2", username: "DevNinja", xp: 11200, level: 23, streak: 7 }, @@ -361,266 +217,169 @@ function LeaderboardTab({ openExternalLink }: { openExternalLink: (url: string) { rank: 5, user_id: "5", username: "ForgeHero", xp: 7200, level: 17, streak: 3 }, ]; - const getRankBadge = (rank: number) => { - if (rank === 1) return { color: "text-yellow-400", bg: "bg-yellow-500/20", icon: "πŸ₯‡" }; - if (rank === 2) return { color: "text-gray-300", bg: "bg-gray-400/20", icon: "πŸ₯ˆ" }; - if (rank === 3) return { color: "text-orange-400", bg: "bg-orange-500/20", icon: "πŸ₯‰" }; - return { color: "text-gray-400", bg: "bg-gray-700/50", icon: null }; - }; + const medals = ["πŸ₯‡", "πŸ₯ˆ", "πŸ₯‰"]; return ( - -
-
-
- - Top Creators This Week +
+ {leaderboard.map((entry) => ( +
+ {medals[entry.rank - 1] || `#${entry.rank}`} +
+

{entry.username}

+

Lvl {entry.level} Β· {entry.xp.toLocaleString()} XP

- Preview + {entry.streak && entry.streak > 0 && ( + {entry.streak}d + )}
- {leaderboard.map((entry) => { - const badge = getRankBadge(entry.rank); - return ( -
-
- {badge.icon || `#${entry.rank}`} -
-
-

{entry.username}

-
- Lvl {entry.level} - {entry.streak && entry.streak > 0 && ( - - {entry.streak}d - - )} -
-
-
-

{entry.xp.toLocaleString()}

-

XP

-
-
- ); - })} - -
- + ))} + +
); } -function OpportunitiesTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { +function JobsTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { + const categories = [ + { label: "Full-Time", icon: Briefcase }, + { label: "Contract", icon: Target }, + { label: "Freelance", icon: Star }, + ]; + return ( - -
-
- - Open Opportunities -
-
-

- Browse job opportunities, contracts, and gigs from the AeThex community. -

- -
- -
-

Quick categories:

-
- {[ - { label: "Full-Time", icon: Briefcase }, - { label: "Contract", icon: Target }, - { label: "Freelance", icon: Star }, - ].map(({ label, icon: Icon }) => ( - - ))} -
-
+
+

Browse opportunities from the AeThex community.

+
+ {categories.map(({ label, icon: Icon }) => ( + + ))}
- + +
); } function QuestsTab({ openExternalLink }: { openExternalLink: (url: string) => Promise }) { const quests: Quest[] = [ - { id: "1", title: "Share Your Work", description: "Post an update to the community feed", xp_reward: 25, completed: false, progress: 0, total: 1, type: "daily" }, - { id: "2", title: "Engage & Support", description: "Like 5 posts from other creators", xp_reward: 15, completed: false, progress: 3, total: 5, type: "daily" }, - { id: "3", title: "Realm Hopper", description: "Visit 3 different realm feeds", xp_reward: 20, completed: true, progress: 3, total: 3, type: "daily" }, - { id: "4", title: "Weekly Contributor", description: "Make 7 posts this week", xp_reward: 150, completed: false, progress: 4, total: 7, type: "weekly" }, + { id: "1", title: "Share Your Work", description: "Post an update", xp_reward: 25, completed: false, progress: 0, total: 1, type: "daily" }, + { id: "2", title: "Engage & Support", description: "Like 5 posts", xp_reward: 15, completed: false, progress: 3, total: 5, type: "daily" }, + { id: "3", title: "Realm Hopper", description: "Visit 3 realms", xp_reward: 20, completed: true, progress: 3, total: 3, type: "daily" }, + { id: "4", title: "Weekly Contributor", description: "Make 7 posts", xp_reward: 150, completed: false, progress: 4, total: 7, type: "weekly" }, ]; - const dailyQuests = quests.filter((q) => q.type === "daily"); - const weeklyQuests = quests.filter((q) => q.type === "weekly"); - - const QuestCard = ({ quest }: { quest: Quest }) => ( -
-
-
- {quest.completed ? : } -
-
-
-

{quest.title}

- +{quest.xp_reward} XP -
-

{quest.description}

-
-
- {!quest.completed && ( -
-
- - {quest.progress}/{quest.total} -
-
- )} -
- ); - return ( - -
-
- - Preview - Quest system coming soon +
+ {quests.map((q) => ( +
+
+
+ {q.completed ? : } + {q.title} +
+ +{q.xp_reward} XP +
+ {!q.completed && ( +
+
+
+
+ {q.progress}/{q.total} +
+ )}
- -
- {dailyQuests.map((quest) => )} -
- -
- - Weekly Quests -
-
- {weeklyQuests.map((quest) => )} -
- - -
- + ))} + +
); } export default function Activity() { const { isActivity, isLoading, user, error, openExternalLink } = useDiscordActivity(); - const [showContent, setShowContent] = useState(false); const [activeTab, setActiveTab] = useState("feed"); - const currentRealm: ArmType = (user?.primary_arm as ArmType) || "labs"; - useEffect(() => { - if (isActivity && !isLoading) { - setShowContent(true); - } - }, [isActivity, isLoading]); + if (isLoading) return ; - if (isLoading) { - return ; - } + if (error) return ( +
+
+ +

Something went wrong

+

{error}

+ +
+
+ ); - if (error) { - return ( -
-
-

Activity Error

-

{error}

-
-

Troubleshooting:

-
    -
  1. Clear your browser cache
  2. -
  3. Close Discord completely
  4. -
  5. Reopen Discord and try again
  6. -
+ if (!isActivity) return ( +
+
+

Discord Activity

+

Open this within Discord to get started.

+ + Visit aethex.dev + +
+
+ ); + + const tabs = [ + { id: "feed", label: "Feed" }, + { id: "realms", label: "Realms" }, + { id: "badges", label: "Badges" }, + { id: "top", label: "Top" }, + { id: "jobs", label: "Jobs" }, + { id: "quests", label: "Quests" }, + ]; + + const realmConfig = ARM_CONFIG[currentRealm]; + const RealmIcon = realmConfig.icon; + + return ( +
+
+
+ {user?.avatar_url && } +
+

{user?.full_name || user?.username}

+
+ + {realmConfig.label} +
-
-
- ); - } - if (!isActivity && !isLoading) { - return ( -
-
-

Discord Activity

-

This page is designed to run as a Discord Activity. Open it within Discord to get started!

- - Visit aethex.dev - +
+ {tabs.map((tab) => ( + + ))} +
+ +
+ {activeTab === "feed" && } + {activeTab === "realms" && } + {activeTab === "badges" && } + {activeTab === "top" && } + {activeTab === "jobs" && } + {activeTab === "quests" && }
- ); - } - - if (user && showContent) { - const realmConfig = ARM_CONFIG[currentRealm]; - const RealmIcon = realmConfig.icon; - - return ( -
-
-
-
- {user.avatar_url && } -
-

{user.full_name || user.username}

- - {realmConfig.label} - -
- -
-
- - - - Feed - Realms - Badges - Top - Jobs - Quests - - -
- - - - - - - - -
-
-
-
- ); - } - - return ; +
+ ); }