Skip to content

Commit 89d9417

Browse files
committed
Initial commit
1 parent f5ed8cb commit 89d9417

File tree

1 file changed

+218
-155
lines changed

1 file changed

+218
-155
lines changed

issue.html

Lines changed: 218 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,166 +1,229 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>GitHub Issue List</title>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>GitHub-Style Issue Tracker</title>
7+
<link
8+
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
9+
rel="stylesheet"
10+
/>
11+
<link
12+
rel="stylesheet"
13+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
14+
/>
15+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
716
<style>
8-
body {
9-
font-family: Arial, sans-serif;
10-
background-color: #f9f9f9;
11-
color: #333;
12-
padding: 20px;
13-
}
14-
h1 {
15-
text-align: center;
16-
color: #333;
17-
}
18-
.issue {
19-
background-color: #fff;
20-
border-radius: 8px;
21-
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
22-
padding: 20px;
23-
margin-bottom: 20px;
24-
border-left: 5px solid #4CAF50;
25-
}
26-
.issue h2 {
27-
color: #333;
28-
margin-top: 0;
29-
}
30-
.issue p {
31-
line-height: 1.6;
32-
}
33-
.issue .comments {
34-
margin-top: 15px;
35-
padding-left: 20px;
36-
border-left: 3px solid #ddd;
37-
}
38-
.comment {
39-
background-color: #f9f9f9;
40-
margin-bottom: 10px;
41-
padding: 10px;
42-
border-radius: 5px;
43-
}
44-
.comment p {
45-
margin: 5px 0;
46-
}
47-
.comment .author {
48-
font-weight: bold;
49-
color: #4CAF50;
50-
}
51-
.comment .date {
52-
font-size: 0.9em;
53-
color: #888;
54-
}
55-
.comment .body {
56-
margin-top: 5px;
57-
}
58-
img {
59-
max-width: 100%;
60-
height: auto;
61-
border-radius: 8px;
62-
}
17+
body {
18+
background-color: #f6f8fa;
19+
}
20+
21+
.issue-card {
22+
background: white;
23+
border: 1px solid #d0d7de;
24+
padding: 16px;
25+
border-radius: 6px;
26+
margin-bottom: 10px;
27+
cursor: pointer;
28+
}
29+
30+
.issue-title {
31+
font-size: 20px;
32+
font-weight: bold;
33+
color: #0969da;
34+
}
35+
36+
.badge-open {
37+
background-color: #2da44e;
38+
color: white;
39+
font-size: 12px;
40+
padding: 5px 8px;
41+
border-radius: 20px;
42+
}
43+
44+
.badge-closed {
45+
background-color: #cf222e;
46+
color: white;
47+
font-size: 12px;
48+
padding: 5px 8px;
49+
border-radius: 20px;
50+
}
51+
52+
.comment-box {
53+
border-left: 3px solid #d0d7de;
54+
padding-left: 10px;
55+
margin-top: 10px;
56+
}
57+
58+
.filter-btn {
59+
cursor: pointer;
60+
}
61+
62+
img {
63+
max-width: 100%;
64+
display: block;
65+
padding: 10px 0;
66+
height: auto;
67+
}
68+
69+
.issue-number {
70+
font-size: 20px;
71+
font-weight: bold;
72+
color: #0057bb;
73+
}
74+
75+
code {
76+
padding: 2px 5px;
77+
78+
background-color: #656c7633;
79+
border-radius: 0.375rem;
80+
color: black;
81+
}
82+
a {
83+
color: #0366d6;
84+
}
6385
</style>
64-
</head>
65-
<body>
66-
67-
<h1>GitHub Issue List</h1>
68-
<div id="issues-container"></div>
69-
7086
<script>
71-
// Function to render issues dynamically
72-
async function fetchIssues() {
73-
try {
74-
const response = await fetch('issues_with_comments_and_images.json'); // Fetch the JSON file
75-
const issuesData = await response.json(); // Parse the JSON data
76-
77-
// Now render the issues
78-
renderIssues(issuesData);
79-
} catch (error) {
80-
console.error("Error fetching the issues data:", error);
81-
alert("There was an error loading the issues.");
82-
}
87+
let issues = [];
88+
89+
async function fetchIssues() {
90+
try {
91+
const response = await fetch("issues_with_comments_and_images.json");
92+
issues = await response.json();
93+
displayIssues(issues);
94+
} catch (error) {
95+
console.error("Error fetching the issues data:", error);
96+
alert("There was an error loading the issues.");
8397
}
84-
85-
// Function to render issues dynamically
86-
function renderIssues(issuesData) {
87-
const container = document.getElementById('issues-container');
88-
issuesData.forEach(issue => {
89-
// Create the issue container
90-
const issueDiv = document.createElement('div');
91-
issueDiv.classList.add('issue');
92-
93-
const numberAndState = document.createElement('h3');
94-
numberAndState.innerHTML = `<strong>Issue #${issue.number}</strong> - State: ${issue.state==="OPEN" ? `<span style="color: green;">Open</span>` : `<span style="color: red;">Closed</span>`}`;
95-
issueDiv.appendChild(numberAndState);
96-
97-
// Title and number
98-
const title = document.createElement('h2');
99-
title.textContent = issue.title;
100-
issueDiv.appendChild(title);
101-
102-
103-
104-
// Body - converting Markdown images into HTML <img> tags
105-
const body = document.createElement('p');
106-
body.innerHTML = processBodyText(issue.body);
107-
issueDiv.appendChild(body);
108-
109-
// Comments Section
110-
if (issue.comments.length > 0) {
111-
const commentsDiv = document.createElement('div');
112-
commentsDiv.classList.add('comments');
113-
114-
issue.comments.forEach(comment => {
115-
const commentDiv = document.createElement('div');
116-
commentDiv.classList.add('comment');
117-
118-
const author = document.createElement('p');
119-
author.classList.add('author');
120-
author.innerHTML = `${comment.author} <span class="date">(${comment.date})</span>`;
121-
commentDiv.appendChild(author);
122-
123-
const body = document.createElement('p');
124-
body.classList.add('body');
125-
body.textContent = comment.body;
126-
commentDiv.appendChild(body);
127-
128-
commentsDiv.appendChild(commentDiv);
129-
});
130-
131-
issueDiv.appendChild(commentsDiv);
132-
}
133-
134-
container.appendChild(issueDiv);
135-
});
98+
}
99+
100+
function fixBodyForImages(markdown) {
101+
return markdown.replace(
102+
/!\[.*?\]\(https:\/\/github\.com\/user-attachments\/assets\/([\w-]+)\)/g,
103+
"![](./downloaded_images/$1)" // Replace with local path
104+
);
105+
}
106+
107+
function displayIssues(issues) {
108+
const issueContainer = document.getElementById("issue-list");
109+
issueContainer.innerHTML = "";
110+
111+
issues.forEach((issue) => {
112+
const issueCard = document.createElement("div");
113+
issueCard.classList.add("issue-card");
114+
115+
issueCard.innerHTML = `
116+
<div class="d-flex justify-content-between align-items-center" onclick="toggleCollapse('issue-${
117+
issue.number
118+
}')">
119+
<div>
120+
<b class="issue-number">#${issue.number}</b>
121+
<i class="fa-solid ${
122+
issue.state === "OPEN"
123+
? "fa-exclamation-circle text-success"
124+
: "fa-check-circle text-danger"
125+
}"></i>
126+
<span class="issue-title">${issue.title}</span>
127+
<span class="${
128+
issue.state === "OPEN"
129+
? "badge-open"
130+
: "badge-closed"
131+
}">${issue.state}</span>
132+
</div>
133+
<i class="fa-solid fa-chevron-down"></i>
134+
</div>
135+
136+
<div id="issue-${issue.number}" class="collapse mt-2">
137+
138+
<p>${marked.parse(fixBodyForImages(issue.body))}</p>
139+
140+
<button class="btn btn-sm btn-outline-secondary mt-2" onclick="toggleCollapse('comments-${
141+
issue.number
142+
}')">
143+
<i class="fa-solid fa-comments"></i> Show Comments ( ${
144+
issue.comments.length
145+
} )
146+
</button>
147+
148+
<div id="comments-${
149+
issue.number
150+
}" class="collapse mt-2">
151+
${
152+
issue.comments.length > 0
153+
? issue.comments
154+
.map(
155+
(comment) => `
156+
<div class="comment-box">
157+
<strong>
158+
<a class="text-black fs-5" href="https://github.com/${
159+
comment.author
160+
}" target="_blank">${comment.author}</a>
161+
</strong>
162+
<p>${marked.parse(comment.body)}</p>
163+
</div>
164+
`
165+
)
166+
.join("")
167+
: "<p>No comments available.</p>"
168+
}
169+
</div>
170+
</div>
171+
`;
172+
173+
issueContainer.appendChild(issueCard);
174+
});
175+
}
176+
177+
function toggleCollapse(id) {
178+
const element = document.getElementById(id);
179+
if (element) {
180+
element.classList.toggle("collapse");
136181
}
182+
}
137183

138-
// Function to process body text and convert Markdown-style images to <img> tags
139-
function processBodyText(text) {
140-
// Regex to match Markdown image syntax (e.g. ![Image](url))
141-
const regex = /!\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g;
142-
143-
// Replace Markdown images with <img> tags pointing to the local 'downloaded_images' folder
144-
return text.replace(regex, (match, altText, url) => {
145-
// Extract image name from the URL
146-
const imageName = url.split('/').pop(); // Get the last part of the URL as the image file name
147-
148-
// Check if the image has an extension and handle accordingly
149-
const imageExtension = imageName.split('.').pop();
150-
const imagePath = `./downloaded_images/${imageName}`;
151-
152-
// Debugging: log the URL and local path to verify
153-
console.log("Original URL:", url); // Check the original URL
154-
console.log("Local Image Path:", imagePath); // Check the local image path
155-
156-
// Return HTML <img> tag
157-
return `<img src="${imagePath}" alt="${altText}" style="max-width: 100%; height: auto;">`;
158-
}).replace(/\n/g, '<br>'); // Replace line breaks with <br> tags
159-
}
184+
function filterIssues(state) {
185+
const filteredIssues =
186+
state === "ALL"
187+
? issues
188+
: issues.filter((issue) => issue.state === state);
189+
displayIssues(filteredIssues);
190+
}
160191

161-
// Call the fetchIssues function when the page loads
162-
fetchIssues();
192+
document.addEventListener("DOMContentLoaded", fetchIssues);
163193
</script>
164-
165-
</body>
194+
</head>
195+
196+
<body class="container-fluid mt-4">
197+
<h2 class="text-center">
198+
<i class="fa-solid fa-bug"></i> GitHub-Style Issue Tracker
199+
</h2>
200+
201+
<div class="d-flex justify-content-center">
202+
<div class="dropdown mb-3">
203+
<button class="btn btn-outline-secondary dropdown-toggle" type="button" id="filterDropdown" data-bs-toggle="dropdown" aria-expanded="false">
204+
<i class="fa-solid fa-filter"></i> Filter Issues
205+
</button>
206+
<ul class="dropdown-menu" aria-labelledby="filterDropdown">
207+
<li><a class="dropdown-item text-success" href="#" onclick="filterIssues('OPEN')">
208+
<i class="fa-solid fa-exclamation-circle"></i> Open Issues
209+
</a></li>
210+
<li><a class="dropdown-item text-danger" href="#" onclick="filterIssues('CLOSED')">
211+
<i class="fa-solid fa-check-circle"></i> Closed Issues
212+
</a></li>
213+
<li><a class="dropdown-item text-secondary" href="#" onclick="filterIssues('ALL')">
214+
<i class="fa-solid fa-list"></i> All Issues
215+
</a></li>
216+
</ul>
217+
</div>
218+
</div>
219+
220+
<div id="issue-list"></div>
221+
222+
<footer class="text-center mt-4">
223+
Developed by <a href="https://github.com/nazmul-rion" target="_blank">Nazmul Islam Rion</a>
224+
</footer>
225+
226+
227+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
228+
</body>
166229
</html>

0 commit comments

Comments
 (0)