Generate an HTML, CSS, and JavaScript high-fidelity prototype based on the following 3-panel user flow from the provided screenshot.
Browse filesThe prototype is for a "Piazza Redesign" (a university Q&A site). The tone of all placeholder text should be professional, clean, and academic.
Global Elements (Persistent on all screens):
Header: A div containing the course title "CS1101" and three div elements styled as "stat boxes" for "All Questions," "Active Users," and "Average Wait Time."
Left Navigation Sidebar: A <nav> element with a ul (list) of links:
"All Questions" (This is the default active link)
"Unanswered (25)" (Styled as a sub-item or badge under "All Questions")
"My Posts"
"Recent"
"Following"
A sub-section labeled "Popular Tags" containing a button styled as a tag for "HW3".
Panel 1: Default View & Post Creation
Summary: This is the default screen the user sees. The "All Questions" link is active, and the main content area shows a "create post" form.
Widgets:
The "All Questions" link in the nav should have an active class (e.g., a yellow background).
The main content area should have a search input widget at the top with placeholder text "Search Questions...".
Below the search, display a <form> element. This form must contain:
A text input widget for "Title" (placeholder: "Lorem ipsum dolor sit amet...").
A textarea widget for "Body" (placeholder: "Lorem ipsum dolor sit amet...").
A text input widget for "Tags" (placeholder: "Lorem, ipsum, dolor").
A button widget with the text "Submit".
Transition 1 -> 2: Submitting the Post
User Action: User clicks the "Submit" button from Panel 1.
Transition:
The <form> in the main content area should disappear (a simple fade-out animation is preferred).
The text of the "Unanswered" badge in the left nav must be updated by JavaScript from "(25)" to "(26)".
The main content area should now display a list of posts (a ul). The top item in this new list should be a li representing the "User's Post" (as seen in Panel 2).
Panel 2: Post Submitted (Confirmation View)
Summary: This screen confirms the post is submitted by showing it in the "All Questions" feed and updating the "Unanswered" count.
Widgets:
The "All Questions" link remains active.
The "Unanswered" badge now shows "(26)".
The main content area shows the "Search Questions..." search input and, below it, a ul list of posts, with "User's Post" at the top.
Transition 2 -> 3: Checking Responses
User Action: User clicks the "My Posts" link in the left navigation sidebar.
Transition:
The active class (yellow background) must move from the "All Questions" link to the "My Posts" link.
The content in the main content area (the "All Questions" feed) should be completely replaced by a new layout.
Panel 3: Viewing a Response
Summary: This screen shows a master-detail view of the user's posts and their responses.
Widgets:
The "My Posts" link is now active.
The main content area should be a two-column (master-detail) layout.
Master Column (left): A ul list of the user's posts. The top post should be highlighted (selected) and include a small badge or text indicating "New Response."
Detail Column (right): This div displays the content of the selected post. It should contain:
The "Title" of the post.
The "Body" of the post.
The "Tags" of the post.
A new section labeled "Response" which contains placeholder text and icons for "Instructor" and "Peer" responses.
- index.html +121 -44
- script.js +184 -67
- style.css +129 -34
|
@@ -3,69 +3,146 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
<script src="https://unpkg.com/feather-icons"></script>
|
| 10 |
-
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
| 11 |
-
<script src="components/navbar.js"></script>
|
| 12 |
-
<script src="components/sidebar.js"></script>
|
| 13 |
-
<script src="components/post-card.js"></script>
|
| 14 |
-
<script src="components/trending-sidebar.js"></script>
|
| 15 |
</head>
|
| 16 |
<body class="bg-gray-50">
|
| 17 |
-
<
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
<i data-feather="alert-circle" class="text-yellow-600"></i>
|
| 27 |
</div>
|
| 28 |
-
<div>
|
| 29 |
-
<div class="text-sm text-gray-
|
| 30 |
-
<div class="text-xl font-bold">
|
| 31 |
</div>
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
<i data-feather="activity" class="text-blue-600"></i>
|
| 36 |
</div>
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
</div>
|
| 41 |
</div>
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
</div>
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
</div>
|
| 51 |
-
</div>
|
| 52 |
|
| 53 |
-
|
| 54 |
-
<
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
<div class="
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
</div>
|
| 64 |
|
| 65 |
<script src="script.js"></script>
|
| 66 |
<script>
|
| 67 |
feather.replace();
|
| 68 |
</script>
|
| 69 |
-
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
| 70 |
</body>
|
| 71 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Piazza Redesign - CS1101</title>
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
<script src="https://unpkg.com/feather-icons"></script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
</head>
|
| 11 |
<body class="bg-gray-50">
|
| 12 |
+
<div class="container mx-auto p-4 max-w-7xl">
|
| 13 |
+
<!-- Header -->
|
| 14 |
+
<header class="bg-white rounded-lg shadow-sm p-4 mb-6">
|
| 15 |
+
<div class="flex justify-between items-center">
|
| 16 |
+
<h1 class="text-2xl font-bold text-gray-800">CS1101</h1>
|
| 17 |
+
<div class="flex space-x-4">
|
| 18 |
+
<div class="stat-box bg-blue-50 border-l-4 border-blue-500">
|
| 19 |
+
<div class="text-sm text-gray-600">All Questions</div>
|
| 20 |
+
<div class="text-xl font-bold">142</div>
|
|
|
|
| 21 |
</div>
|
| 22 |
+
<div class="stat-box bg-green-50 border-l-4 border-green-500">
|
| 23 |
+
<div class="text-sm text-gray-600">Active Users</div>
|
| 24 |
+
<div class="text-xl font-bold">24</div>
|
| 25 |
</div>
|
| 26 |
+
<div class="stat-box bg-purple-50 border-l-4 border-purple-500">
|
| 27 |
+
<div class="text-sm text-gray-600">Avg Wait Time</div>
|
| 28 |
+
<div class="text-xl font-bold">18 min</div>
|
|
|
|
| 29 |
</div>
|
| 30 |
+
</div>
|
| 31 |
+
</div>
|
| 32 |
+
</header>
|
| 33 |
+
|
| 34 |
+
<div class="flex gap-6">
|
| 35 |
+
<!-- Left Navigation Sidebar -->
|
| 36 |
+
<nav class="w-64 bg-white rounded-lg shadow-sm p-4 h-fit sticky top-4">
|
| 37 |
+
<ul class="space-y-1">
|
| 38 |
+
<li>
|
| 39 |
+
<a href="#" class="nav-item active" id="all-questions-link">
|
| 40 |
+
<i data-feather="inbox" class="w-4 h-4"></i>
|
| 41 |
+
<span>All Questions</span>
|
| 42 |
+
</a>
|
| 43 |
+
<a href="#" class="nav-subitem ml-8" id="unanswered-link">
|
| 44 |
+
<i data-feather="help-circle" class="w-4 h-4"></i>
|
| 45 |
+
<span>Unanswered (<span id="unanswered-count">25</span>)</span>
|
| 46 |
+
</a>
|
| 47 |
+
</li>
|
| 48 |
+
<li>
|
| 49 |
+
<a href="#" class="nav-item" id="my-posts-link">
|
| 50 |
+
<i data-feather="user" class="w-4 h-4"></i>
|
| 51 |
+
<span>My Posts</span>
|
| 52 |
+
</a>
|
| 53 |
+
</li>
|
| 54 |
+
<li>
|
| 55 |
+
<a href="#" class="nav-item">
|
| 56 |
+
<i data-feather="clock" class="w-4 h-4"></i>
|
| 57 |
+
<span>Recent</span>
|
| 58 |
+
</a>
|
| 59 |
+
</li>
|
| 60 |
+
<li>
|
| 61 |
+
<a href="#" class="nav-item">
|
| 62 |
+
<i data-feather="bookmark" class="w-4 h-4"></i>
|
| 63 |
+
<span>Following</span>
|
| 64 |
+
</a>
|
| 65 |
+
</li>
|
| 66 |
+
</ul>
|
| 67 |
+
|
| 68 |
+
<div class="mt-8">
|
| 69 |
+
<h3 class="text-sm font-medium text-gray-500 mb-2 flex items-center">
|
| 70 |
+
<i data-feather="tag" class="w-4 h-4 mr-2"></i>
|
| 71 |
+
Popular Tags
|
| 72 |
+
</h3>
|
| 73 |
+
<div class="flex flex-wrap gap-2">
|
| 74 |
+
<span class="tag">HW3</span>
|
| 75 |
+
<span class="tag">Midterm</span>
|
| 76 |
+
<span class="tag">Project</span>
|
| 77 |
</div>
|
| 78 |
</div>
|
| 79 |
+
</nav>
|
| 80 |
+
|
| 81 |
+
<!-- Main Content Area -->
|
| 82 |
+
<main class="flex-1" id="main-content">
|
| 83 |
+
<!-- Panel 1: Default View & Post Creation -->
|
| 84 |
+
<div id="panel-1">
|
| 85 |
+
<div class="search-container mb-6">
|
| 86 |
+
<input type="text" placeholder="Search Questions..." class="search-input">
|
| 87 |
+
<i data-feather="search" class="search-icon"></i>
|
| 88 |
</div>
|
| 89 |
+
|
| 90 |
+
<form id="post-form" class="bg-white rounded-lg shadow-sm p-6">
|
| 91 |
+
<h2 class="text-xl font-bold mb-4">Create New Post</h2>
|
| 92 |
+
<div class="mb-4">
|
| 93 |
+
<label for="post-title" class="block text-sm font-medium text-gray-700 mb-1">Title</label>
|
| 94 |
+
<input type="text" id="post-title" placeholder="Lorem ipsum dolor sit amet..." class="form-input">
|
| 95 |
+
</div>
|
| 96 |
+
<div class="mb-4">
|
| 97 |
+
<label for="post-body" class="block text-sm font-medium text-gray-700 mb-1">Body</label>
|
| 98 |
+
<textarea id="post-body" rows="5" placeholder="Lorem ipsum dolor sit amet..." class="form-textarea"></textarea>
|
| 99 |
+
</div>
|
| 100 |
+
<div class="mb-6">
|
| 101 |
+
<label for="post-tags" class="block text-sm font-medium text-gray-700 mb-1">Tags</label>
|
| 102 |
+
<input type="text" id="post-tags" placeholder="Lorem, ipsum, dolor" class="form-input">
|
| 103 |
+
</div>
|
| 104 |
+
<button type="submit" class="submit-btn">Submit</button>
|
| 105 |
+
</form>
|
| 106 |
+
</div>
|
| 107 |
+
|
| 108 |
+
<!-- Panel 2: Post Submitted (Hidden by default) -->
|
| 109 |
+
<div id="panel-2" class="hidden">
|
| 110 |
+
<div class="search-container mb-6">
|
| 111 |
+
<input type="text" placeholder="Search Questions..." class="search-input">
|
| 112 |
+
<i data-feather="search" class="search-icon"></i>
|
| 113 |
</div>
|
| 114 |
+
|
| 115 |
+
<ul id="posts-list" class="space-y-4">
|
| 116 |
+
<!-- Posts will be inserted here by JavaScript -->
|
| 117 |
+
</ul>
|
| 118 |
</div>
|
|
|
|
| 119 |
|
| 120 |
+
<!-- Panel 3: Viewing Responses (Hidden by default) -->
|
| 121 |
+
<div id="panel-3" class="hidden">
|
| 122 |
+
<div class="flex gap-6">
|
| 123 |
+
<!-- Master Column -->
|
| 124 |
+
<div class="w-1/3">
|
| 125 |
+
<h2 class="text-xl font-bold mb-4">My Posts</h2>
|
| 126 |
+
<ul id="my-posts-list" class="space-y-2">
|
| 127 |
+
<!-- User posts will be inserted here by JavaScript -->
|
| 128 |
+
</ul>
|
| 129 |
+
</div>
|
| 130 |
+
|
| 131 |
+
<!-- Detail Column -->
|
| 132 |
+
<div class="flex-1 bg-white rounded-lg shadow-sm p-6">
|
| 133 |
+
<div id="post-detail">
|
| 134 |
+
<!-- Post detail will be inserted here by JavaScript -->
|
| 135 |
+
</div>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
</div>
|
| 139 |
+
</main>
|
| 140 |
+
</div>
|
| 141 |
</div>
|
| 142 |
|
| 143 |
<script src="script.js"></script>
|
| 144 |
<script>
|
| 145 |
feather.replace();
|
| 146 |
</script>
|
|
|
|
| 147 |
</body>
|
| 148 |
</html>
|
|
@@ -1,82 +1,199 @@
|
|
| 1 |
-
|
| 2 |
-
// Simulate live stats updates
|
| 3 |
-
function updateDashboardStats() {
|
| 4 |
-
const unrespondedEl = document.querySelector('.border-yellow-500 + div .text-xl');
|
| 5 |
-
const activeEl = document.querySelector('.border-blue-500 + div .text-xl');
|
| 6 |
-
const waitTimeEl = document.querySelector('.border-green-500 + div .text-xl');
|
| 7 |
-
|
| 8 |
-
// Random fluctuations to make stats feel alive
|
| 9 |
-
const newUnresponded = Math.max(5, Math.min(20, 12 + Math.floor(Math.random() * 5) - 2));
|
| 10 |
-
const newActive = Math.max(15, Math.min(35, 24 + Math.floor(Math.random() * 7) - 3));
|
| 11 |
-
const newWaitTime = Math.max(5, Math.min(30, 18 + Math.floor(Math.random() * 10) - 5));
|
| 12 |
-
|
| 13 |
-
unrespondedEl.textContent = newUnresponded;
|
| 14 |
-
activeEl.textContent = newActive;
|
| 15 |
-
waitTimeEl.textContent = `${newWaitTime} min`;
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
document.addEventListener('DOMContentLoaded', function() {
|
| 19 |
-
//
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
//
|
| 24 |
-
const
|
| 25 |
{
|
| 26 |
id: 1,
|
| 27 |
-
title: "
|
| 28 |
-
|
| 29 |
-
tags: ["
|
| 30 |
-
status: "unanswered",
|
| 31 |
-
responses: 0,
|
| 32 |
-
upvotes: 5,
|
| 33 |
-
confidence: 20,
|
| 34 |
-
author: "Jane D.",
|
| 35 |
-
time: "2 hours ago"
|
| 36 |
-
},
|
| 37 |
-
{
|
| 38 |
-
id: 2,
|
| 39 |
-
title: "Best resources for learning React hooks?",
|
| 40 |
-
content: "Looking for good tutorials beyond the official documentation...",
|
| 41 |
-
tags: ["Programming", "React"],
|
| 42 |
-
status: "answered",
|
| 43 |
responses: 3,
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
author: "John S.",
|
| 47 |
-
time: "1 day ago"
|
| 48 |
},
|
| 49 |
{
|
| 50 |
-
id:
|
| 51 |
-
title: "
|
| 52 |
-
|
| 53 |
-
tags: ["
|
| 54 |
-
status: "unanswered",
|
| 55 |
responses: 1,
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
author: "Alex M.",
|
| 59 |
-
time: "30 minutes ago"
|
| 60 |
}
|
| 61 |
];
|
| 62 |
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
});
|
| 70 |
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
}
|
|
|
|
| 81 |
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
```javascript
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
document.addEventListener('DOMContentLoaded', function() {
|
| 3 |
+
// DOM Elements
|
| 4 |
+
const postForm = document.getElementById('post-form');
|
| 5 |
+
const panel1 = document.getElementById('panel-1');
|
| 6 |
+
const panel2 = document.getElementById('panel-2');
|
| 7 |
+
const panel3 = document.getElementById('panel-3');
|
| 8 |
+
const postsList = document.getElementById('posts-list');
|
| 9 |
+
const myPostsList = document.getElementById('my-posts-list');
|
| 10 |
+
const postDetail = document.getElementById('post-detail');
|
| 11 |
+
const unansweredCount = document.getElementById('unanswered-count');
|
| 12 |
+
const allQuestionsLink = document.getElementById('all-questions-link');
|
| 13 |
+
const myPostsLink = document.getElementById('my-posts-link');
|
| 14 |
+
const unansweredLink = document.getElementById('unanswered-link');
|
| 15 |
|
| 16 |
+
// Sample data
|
| 17 |
+
const samplePosts = [
|
| 18 |
{
|
| 19 |
id: 1,
|
| 20 |
+
title: "Understanding recursion in binary trees",
|
| 21 |
+
body: "I'm having trouble understanding how recursion works with binary tree traversal. Can someone explain the base case and recursive case?",
|
| 22 |
+
tags: ["Recursion", "Binary Trees", "Data Structures"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
responses: 3,
|
| 24 |
+
isMine: false,
|
| 25 |
+
hasNewResponse: false
|
|
|
|
|
|
|
| 26 |
},
|
| 27 |
{
|
| 28 |
+
id: 2,
|
| 29 |
+
title: "Clarification on HW3 problem 2",
|
| 30 |
+
body: "The problem statement says we need to implement a function with O(n) time complexity, but I'm not sure what approach to take.",
|
| 31 |
+
tags: ["Homework", "Algorithms"],
|
|
|
|
| 32 |
responses: 1,
|
| 33 |
+
isMine: false,
|
| 34 |
+
hasNewResponse: false
|
|
|
|
|
|
|
| 35 |
}
|
| 36 |
];
|
| 37 |
|
| 38 |
+
let userPosts = [];
|
| 39 |
+
|
| 40 |
+
// Form submission
|
| 41 |
+
postForm.addEventListener('submit', function(e) {
|
| 42 |
+
e.preventDefault();
|
| 43 |
+
|
| 44 |
+
const title = document.getElementById('post-title').value;
|
| 45 |
+
const body = document.getElementById('post-body').value;
|
| 46 |
+
const tags = document.getElementById('post-tags').value.split(',').map(tag => tag.trim());
|
| 47 |
+
|
| 48 |
+
// Create new post
|
| 49 |
+
const newPost = {
|
| 50 |
+
id: Date.now(),
|
| 51 |
+
title,
|
| 52 |
+
body,
|
| 53 |
+
tags,
|
| 54 |
+
responses: 0,
|
| 55 |
+
isMine: true,
|
| 56 |
+
hasNewResponse: false
|
| 57 |
+
};
|
| 58 |
+
|
| 59 |
+
// Add to user posts
|
| 60 |
+
userPosts.unshift(newPost);
|
| 61 |
+
|
| 62 |
+
// Update UI
|
| 63 |
+
updateUnansweredCount();
|
| 64 |
+
showPanel2(newPost);
|
| 65 |
+
|
| 66 |
+
// Reset form
|
| 67 |
+
postForm.reset();
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
// Navigation
|
| 71 |
+
allQuestionsLink.addEventListener('click', function(e) {
|
| 72 |
+
e.preventDefault();
|
| 73 |
+
setActiveNav(allQuestionsLink);
|
| 74 |
+
showPanel1();
|
| 75 |
});
|
| 76 |
|
| 77 |
+
myPostsLink.addEventListener('click', function(e) {
|
| 78 |
+
e.preventDefault();
|
| 79 |
+
setActiveNav(myPostsLink);
|
| 80 |
+
showPanel3();
|
| 81 |
+
});
|
| 82 |
+
|
| 83 |
+
// Helper functions
|
| 84 |
+
function updateUnansweredCount() {
|
| 85 |
+
const currentCount = parseInt(unansweredCount.textContent);
|
| 86 |
+
unansweredCount.textContent = currentCount + 1;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
function setActiveNav(activeElement) {
|
| 90 |
+
document.querySelectorAll('.nav-item').forEach(item => {
|
| 91 |
+
item.classList.remove('active');
|
| 92 |
+
});
|
| 93 |
+
activeElement.classList.add('active');
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
function showPanel1() {
|
| 97 |
+
panel1.classList.remove('hidden');
|
| 98 |
+
panel2.classList.add('hidden');
|
| 99 |
+
panel3.classList.add('hidden');
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
function showPanel2(newPost) {
|
| 103 |
+
// Add fade out animation to form
|
| 104 |
+
postForm.classList.add('fade-out');
|
| 105 |
+
|
| 106 |
+
setTimeout(() => {
|
| 107 |
+
panel1.classList.add('hidden');
|
| 108 |
+
panel2.classList.remove('hidden');
|
| 109 |
+
|
| 110 |
+
// Add sample posts + new post to the list
|
| 111 |
+
postsList.innerHTML = '';
|
| 112 |
+
|
| 113 |
+
// Add new post first
|
| 114 |
+
addPostToPanel2(newPost);
|
| 115 |
+
|
| 116 |
+
// Add sample posts
|
| 117 |
+
samplePosts.forEach(post => {
|
| 118 |
+
addPostToPanel2(post);
|
| 119 |
+
});
|
| 120 |
+
|
| 121 |
+
// Reset form animation
|
| 122 |
+
postForm.classList.remove('fade-out');
|
| 123 |
+
}, 300);
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
function addPostToPanel2(post) {
|
| 127 |
+
const postItem = document.createElement('li');
|
| 128 |
+
postItem.className = 'post-card';
|
| 129 |
+
postItem.innerHTML = `
|
| 130 |
+
<h3 class="text-lg font-bold mb-2">${post.title}</h3>
|
| 131 |
+
<p class="text-gray-600 mb-3">${post.body}</p>
|
| 132 |
+
<div class="flex flex-wrap gap-2 mb-3">
|
| 133 |
+
${post.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
|
| 134 |
+
</div>
|
| 135 |
+
<div class="flex justify-between text-sm text-gray-500">
|
| 136 |
+
<span>${post.responses} ${post.responses === 1 ? 'response' : 'responses'}</span>
|
| 137 |
+
<span>Just now</span>
|
| 138 |
+
</div>
|
| 139 |
+
`;
|
| 140 |
+
postsList.prepend(postItem);
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
function showPanel3() {
|
| 144 |
+
panel1.classList.add('hidden');
|
| 145 |
+
panel2.classList.add('hidden');
|
| 146 |
+
panel3.classList.remove('hidden');
|
| 147 |
+
|
| 148 |
+
// Populate user posts
|
| 149 |
+
myPostsList.innerHTML = '';
|
| 150 |
+
userPosts.forEach((post, index) => {
|
| 151 |
+
const postItem = document.createElement('li');
|
| 152 |
+
postItem.className = `post-card cursor-pointer ${index === 0 ? 'selected' : ''}`;
|
| 153 |
+
postItem.innerHTML = `
|
| 154 |
+
<h3 class="text-lg font-bold mb-2">${post.title}</h3>
|
| 155 |
+
${post.hasNewResponse ? '<span class="new-response-badge inline-block mb-2">New Response</span>' : ''}
|
| 156 |
+
<div class="flex flex-wrap gap-2 mb-2">
|
| 157 |
+
${post.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
|
| 158 |
+
</div>
|
| 159 |
+
<div class="text-sm text-gray-500">
|
| 160 |
+
${post.responses} ${post.responses === 1 ? 'response' : 'responses'}
|
| 161 |
+
</div>
|
| 162 |
+
`;
|
| 163 |
+
|
| 164 |
+
postItem.addEventListener('click', () => {
|
| 165 |
+
document.querySelectorAll('.post-card').forEach(card => {
|
| 166 |
+
card.classList.remove('selected');
|
| 167 |
+
});
|
| 168 |
+
postItem.classList.add('selected');
|
| 169 |
+
showPostDetail(post);
|
| 170 |
+
});
|
| 171 |
+
|
| 172 |
+
myPostsList.appendChild(postItem);
|
| 173 |
+
});
|
| 174 |
|
| 175 |
+
// Show detail of first post
|
| 176 |
+
if (userPosts.length > 0) {
|
| 177 |
+
showPostDetail(userPosts[0]);
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
|
| 181 |
+
function showPostDetail(post) {
|
| 182 |
+
postDetail.innerHTML = `
|
| 183 |
+
<h2 class="text-2xl font-bold mb-4">${post.title}</h2>
|
| 184 |
+
<div class="prose max-w-none mb-6">
|
| 185 |
+
<p>${post.body}</p>
|
| 186 |
+
</div>
|
| 187 |
+
<div class="flex flex-wrap gap-2 mb-8">
|
| 188 |
+
${post.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
|
| 189 |
+
</div>
|
| 190 |
+
|
| 191 |
+
<h3 class="text-xl font-bold mb-4">Responses</h3>
|
| 192 |
+
<div class="space-y-6">
|
| 193 |
+
<div class="response-card">
|
| 194 |
+
<div class="flex items-start mb-2">
|
| 195 |
+
<div class="bg-blue-100 p-2 rounded-full mr-3">
|
| 196 |
+
<i data-feather="user-check" class="text-blue-600 w-5 h-5"></i>
|
| 197 |
+
</div>
|
| 198 |
+
<div>
|
| 199 |
+
<h4
|
|
@@ -1,54 +1,149 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
-
|
| 4 |
-
--danger: #ef4444;
|
| 5 |
-
--warning: #f59e0b;
|
| 6 |
-
--success: #10b981;
|
| 7 |
}
|
| 8 |
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
| 11 |
}
|
| 12 |
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
}
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
.post-card {
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
}
|
| 20 |
|
| 21 |
.post-card:hover {
|
| 22 |
transform: translateY(-2px);
|
| 23 |
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
| 24 |
}
|
| 25 |
-
/* Dashboard stats bubbles */
|
| 26 |
-
.dashboard-stat {
|
| 27 |
-
transition: all 0.3s ease;
|
| 28 |
-
}
|
| 29 |
|
| 30 |
-
.
|
| 31 |
-
|
| 32 |
-
|
| 33 |
}
|
| 34 |
|
| 35 |
-
.
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
|
|
|
|
|
|
| 39 |
}
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
border: 2px solid white;
|
| 45 |
-
position: absolute;
|
| 46 |
-
top: -3px;
|
| 47 |
-
transform: translateX(-50%);
|
| 48 |
}
|
| 49 |
|
| 50 |
-
@
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
}
|
| 54 |
}
|
|
|
|
| 1 |
+
/* Base Styles */
|
| 2 |
+
body {
|
| 3 |
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
|
|
|
|
|
|
|
|
| 4 |
}
|
| 5 |
|
| 6 |
+
/* Header & Stats */
|
| 7 |
+
.stat-box {
|
| 8 |
+
padding: 1rem;
|
| 9 |
+
border-radius: 0.5rem;
|
| 10 |
+
min-width: 140px;
|
| 11 |
}
|
| 12 |
|
| 13 |
+
/* Navigation */
|
| 14 |
+
.nav-item {
|
| 15 |
+
display: flex;
|
| 16 |
+
align-items: center;
|
| 17 |
+
padding: 0.75rem 1rem;
|
| 18 |
+
border-radius: 0.375rem;
|
| 19 |
+
color: #4b5563;
|
| 20 |
+
transition: all 0.2s;
|
| 21 |
}
|
| 22 |
|
| 23 |
+
.nav-item:hover {
|
| 24 |
+
background-color: #f3f4f6;
|
| 25 |
+
color: #111827;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
.nav-item.active {
|
| 29 |
+
background-color: #fef3c7;
|
| 30 |
+
color: #92400e;
|
| 31 |
+
font-weight: 500;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.nav-subitem {
|
| 35 |
+
display: flex;
|
| 36 |
+
align-items: center;
|
| 37 |
+
padding: 0.5rem 1rem 0.5rem 2rem;
|
| 38 |
+
border-radius: 0.375rem;
|
| 39 |
+
color: #4b5563;
|
| 40 |
+
font-size: 0.875rem;
|
| 41 |
+
transition: all 0.2s;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
.nav-subitem:hover {
|
| 45 |
+
background-color: #f3f4f6;
|
| 46 |
+
color: #111827;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/* Tags */
|
| 50 |
+
.tag {
|
| 51 |
+
display: inline-block;
|
| 52 |
+
background-color: #e0e7ff;
|
| 53 |
+
color: #4f46e5;
|
| 54 |
+
font-size: 0.75rem;
|
| 55 |
+
padding: 0.25rem 0.75rem;
|
| 56 |
+
border-radius: 9999px;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
/* Search */
|
| 60 |
+
.search-container {
|
| 61 |
+
position: relative;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
.search-input {
|
| 65 |
+
width: 100%;
|
| 66 |
+
padding: 0.75rem 1rem 0.75rem 2.5rem;
|
| 67 |
+
border: 1px solid #e5e7eb;
|
| 68 |
+
border-radius: 0.5rem;
|
| 69 |
+
transition: all 0.2s;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.search-input:focus {
|
| 73 |
+
outline: none;
|
| 74 |
+
border-color: #6366f1;
|
| 75 |
+
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.search-icon {
|
| 79 |
+
position: absolute;
|
| 80 |
+
left: 1rem;
|
| 81 |
+
top: 50%;
|
| 82 |
+
transform: translateY(-50%);
|
| 83 |
+
color: #9ca3af;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/* Form Elements */
|
| 87 |
+
.form-input, .form-textarea {
|
| 88 |
+
width: 100%;
|
| 89 |
+
padding: 0.5rem 0.75rem;
|
| 90 |
+
border: 1px solid #d1d5db;
|
| 91 |
+
border-radius: 0.375rem;
|
| 92 |
+
transition: all 0.2s;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
.form-input:focus, .form-textarea:focus {
|
| 96 |
+
outline: none;
|
| 97 |
+
border-color: #6366f1;
|
| 98 |
+
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.submit-btn {
|
| 102 |
+
background-color: #4f46e5;
|
| 103 |
+
color: white;
|
| 104 |
+
padding: 0.75rem 1.5rem;
|
| 105 |
+
border-radius: 0.375rem;
|
| 106 |
+
font-weight: 500;
|
| 107 |
+
transition: all 0.2s;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
.submit-btn:hover {
|
| 111 |
+
background-color: #4338ca;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/* Posts */
|
| 115 |
.post-card {
|
| 116 |
+
background-color: white;
|
| 117 |
+
border-radius: 0.5rem;
|
| 118 |
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
| 119 |
+
padding: 1.5rem;
|
| 120 |
+
transition: all 0.2s;
|
| 121 |
}
|
| 122 |
|
| 123 |
.post-card:hover {
|
| 124 |
transform: translateY(-2px);
|
| 125 |
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
| 126 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
+
.post-card.selected {
|
| 129 |
+
border-left: 4px solid #4f46e5;
|
| 130 |
+
background-color: #f5f3ff;
|
| 131 |
}
|
| 132 |
|
| 133 |
+
.new-response-badge {
|
| 134 |
+
background-color: #fef3c7;
|
| 135 |
+
color: #92400e;
|
| 136 |
+
font-size: 0.75rem;
|
| 137 |
+
padding: 0.25rem 0.5rem;
|
| 138 |
+
border-radius: 9999px;
|
| 139 |
}
|
| 140 |
+
|
| 141 |
+
/* Animations */
|
| 142 |
+
.fade-out {
|
| 143 |
+
animation: fadeOut 0.3s forwards;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
}
|
| 145 |
|
| 146 |
+
@keyframes fadeOut {
|
| 147 |
+
from { opacity: 1; }
|
| 148 |
+
to { opacity: 0; }
|
|
|
|
| 149 |
}
|