Skip to content

Commit b745bd6

Browse files
feat(pages): add roadmap page
1 parent 0768394 commit b745bd6

File tree

5 files changed

+260
-0
lines changed

5 files changed

+260
-0
lines changed

_config_theme.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ navbar-links:
1818
- Status: "https://status.LizardByte.dev"
1919
Development:
2020
- Contributing: "https://docs.lizardbyte.dev/latest/developers/contributing.html"
21+
- Roadmap: "roadmap"
2122
- Dashboard: "https://app.lizardbyte.dev/dashboard"
2223
- Dev Status: "https://status-dev.LizardByte.dev"
2324
avatar: "/assets/img/navbar-avatar.png"

_sass/styles.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ body {
2020
background-color: var(--navbar-col) !important;
2121
}
2222

23+
.modal-content {
24+
background-color: var(--footer-col) !important;
25+
}
26+
2327
/* in line code */
2428
code {
2529
color: var(--mid-col);

assets/img/banners/roadmap.jpg

187 KB
Loading

assets/js/roadmap.js

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
document.addEventListener('DOMContentLoaded', function() {
2+
const issuesContainer = document.getElementById('issues-container');
3+
const issueModal = new bootstrap.Modal(document.getElementById('issueModal'));
4+
const issueModalBody = document.getElementById('issueModalBody');
5+
const issueModalLabel = document.getElementById('issueModalLabel');
6+
const viewOnGithubBtn = document.getElementById('viewOnGithub');
7+
8+
// GitHub API endpoint for your repository's issues
9+
const apiUrl = 'https://api.github.com/repos/LizardByte/roadmap/issues?state=open&labels=planned&per_page=100';
10+
11+
fetch(apiUrl)
12+
.then(response => {
13+
if (!response.ok) {
14+
throw new Error('Network response was not ok');
15+
}
16+
return response.json();
17+
})
18+
.then(issues => {
19+
if (issues.length === 0) {
20+
issuesContainer.innerHTML = '<p>No roadmap items found.</p>';
21+
return;
22+
}
23+
24+
// Clear loading message
25+
issuesContainer.innerHTML = '';
26+
27+
// Create issues list
28+
const issuesList = document.createElement('div');
29+
issuesList.className = 'row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4';
30+
31+
issues.forEach(issue => {
32+
const issueCol = document.createElement('div');
33+
issueCol.className = 'col';
34+
35+
const issueEl = document.createElement('div');
36+
issueEl.className = 'card h-100 shadow border-0 rounded-0';
37+
issueEl.style.cursor = 'pointer';
38+
39+
// Store issue data for modal
40+
issueEl.dataset.issue = JSON.stringify(issue);
41+
42+
// Click event to show modal
43+
issueEl.addEventListener('click', function() {
44+
const issueData = JSON.parse(this.dataset.issue);
45+
displayIssueInModal(issueData);
46+
});
47+
48+
const cardBody = document.createElement('div');
49+
cardBody.className = 'card-body text-white p-4 rounded-0';
50+
51+
// Issue title
52+
const titleEl = document.createElement('h5');
53+
titleEl.className = 'card-title mb-3 fw-bolder crowdin-ignore';
54+
const titleText = document.createElement('span');
55+
titleText.textContent = issue.title;
56+
titleText.className = 'text-decoration-none';
57+
titleEl.appendChild(titleText);
58+
59+
// Issue metadata
60+
const metaEl = document.createElement('div');
61+
metaEl.className = 'd-flex justify-content-between mb-2 small';
62+
63+
// Issue number
64+
const numberEl = document.createElement('span');
65+
numberEl.className = 'badge bg-secondary crowdin-ignore';
66+
numberEl.textContent = `#${issue.number}`;
67+
68+
// Issue date
69+
const dateEl = document.createElement('span');
70+
dateEl.className = 'crowdin-ignore';
71+
const createdDate = new Date(issue.created_at);
72+
dateEl.textContent = createdDate.toLocaleDateString();
73+
74+
metaEl.appendChild(numberEl);
75+
metaEl.appendChild(dateEl);
76+
77+
// Labels
78+
const labelsEl = document.createElement('div');
79+
labelsEl.className = 'd-flex flex-wrap gap-1 mb-2';
80+
81+
issue.labels.forEach(label => {
82+
const labelEl = document.createElement('span');
83+
labelEl.className = 'badge crowdin-ignore';
84+
labelEl.textContent = label.name;
85+
labelEl.style.backgroundColor = `#${label.color}`;
86+
87+
// Determine if label text should be dark or light based on background
88+
const r = parseInt(label.color.substring(0, 2), 16);
89+
const g = parseInt(label.color.substring(2, 4), 16);
90+
const b = parseInt(label.color.substring(4, 6), 16);
91+
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
92+
labelEl.style.color = brightness > 125 ? '#000' : '#fff';
93+
94+
labelsEl.appendChild(labelEl);
95+
});
96+
97+
// Add all elements to the card body
98+
cardBody.appendChild(titleEl);
99+
cardBody.appendChild(metaEl);
100+
cardBody.appendChild(labelsEl);
101+
102+
issueEl.appendChild(cardBody);
103+
issueCol.appendChild(issueEl);
104+
issuesList.appendChild(issueCol);
105+
});
106+
107+
issuesContainer.appendChild(issuesList);
108+
})
109+
.catch(error => {
110+
issuesContainer.innerHTML = `<p class="text-danger">Error loading roadmap items: ${error.message}</p>`;
111+
});
112+
113+
// Function to display issue in modal
114+
function displayIssueInModal(issue) {
115+
// Set modal title
116+
issueModalLabel.textContent = `${issue.title} (#${issue.number})`;
117+
118+
// Set GitHub link
119+
viewOnGithubBtn.href = issue.html_url;
120+
121+
// Create modal content
122+
let modalContent = document.createElement('div');
123+
124+
// Issue metadata
125+
const metaEl = document.createElement('div');
126+
metaEl.className = 'd-flex justify-content-between mb-3';
127+
128+
// Issue created date
129+
const createdEl = document.createElement('span');
130+
const createdLabel = document.createElement('strong');
131+
createdLabel.textContent = 'Created:';
132+
createdEl.appendChild(createdLabel);
133+
createdEl.appendChild(document.createTextNode(' '));
134+
135+
const createdValue = document.createElement('span');
136+
createdValue.className = 'crowdin-ignore';
137+
const createdDate = new Date(issue.created_at);
138+
createdValue.textContent = createdDate.toLocaleDateString();
139+
createdEl.appendChild(createdValue);
140+
141+
// Issue author
142+
const authorEl = document.createElement('span');
143+
const authorLabel = document.createElement('strong');
144+
authorLabel.textContent = 'By:';
145+
authorEl.appendChild(authorLabel);
146+
authorEl.appendChild(document.createTextNode(' '));
147+
148+
const authorValue = document.createElement('span');
149+
authorValue.className = 'crowdin-ignore';
150+
authorValue.textContent = issue.user.login;
151+
authorEl.appendChild(authorValue);
152+
153+
metaEl.appendChild(createdEl);
154+
metaEl.appendChild(authorEl);
155+
modalContent.appendChild(metaEl);
156+
157+
// Labels
158+
if (issue.labels && issue.labels.length > 0) {
159+
const labelsContainer = document.createElement('div');
160+
labelsContainer.className = 'mb-3';
161+
162+
const labelsTitle = document.createElement('strong');
163+
labelsTitle.textContent = 'Labels:';
164+
labelsContainer.appendChild(labelsTitle);
165+
166+
const labelsEl = document.createElement('div');
167+
labelsEl.className = 'd-flex flex-wrap gap-1 mt-1';
168+
169+
issue.labels.forEach(label => {
170+
const labelEl = document.createElement('span');
171+
labelEl.className = 'badge crowdin-ignore';
172+
labelEl.textContent = label.name;
173+
labelEl.style.backgroundColor = `#${label.color}`;
174+
175+
// Determine if label text should be dark or light based on background
176+
const r = parseInt(label.color.substring(0, 2), 16);
177+
const g = parseInt(label.color.substring(2, 4), 16);
178+
const b = parseInt(label.color.substring(4, 6), 16);
179+
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
180+
labelEl.style.color = brightness > 125 ? '#000' : '#fff';
181+
182+
labelsEl.appendChild(labelEl);
183+
});
184+
185+
labelsContainer.appendChild(labelsEl);
186+
modalContent.appendChild(labelsContainer);
187+
}
188+
189+
// Issue body
190+
const bodyContainer = document.createElement('div');
191+
bodyContainer.className = 'mt-3 p-3 rounded-0';
192+
193+
if (issue.body) {
194+
// Create a container with crowdin-ignore class for the entire rendered content
195+
const markdownContainer = document.createElement('div');
196+
markdownContainer.className = 'crowdin-ignore';
197+
198+
// Use Marked to parse the markdown
199+
markdownContainer.innerHTML = marked.parse(issue.body);
200+
201+
// Add the rendered content to the body container
202+
bodyContainer.appendChild(markdownContainer);
203+
} else {
204+
const noContentMsg = document.createElement('div');
205+
noContentMsg.textContent = 'No description provided.';
206+
bodyContainer.appendChild(noContentMsg);
207+
}
208+
209+
modalContent.appendChild(bodyContainer);
210+
211+
// Set modal content
212+
issueModalBody.innerHTML = '';
213+
issueModalBody.appendChild(modalContent);
214+
215+
// Show modal
216+
issueModal.show();
217+
}
218+
});

roadmap.html

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: Roadmap
3+
layout: page
4+
full-width: true
5+
cover-img:
6+
- /assets/img/banners/roadmap.jpg
7+
ext-js:
8+
- https://cdn.jsdelivr.net/npm/[email protected]/marked.min.js
9+
js:
10+
- /assets/js/roadmap.js
11+
---
12+
13+
<div class="container my-4">
14+
<h1 class="mb-4">LizardByte Roadmap</h1>
15+
<div id="issues-container">
16+
<p>Loading roadmap items...</p>
17+
</div>
18+
</div>
19+
20+
<!-- Modal -->
21+
<div class="modal fade" id="issueModal" tabindex="-1" aria-labelledby="issueModalLabel" aria-hidden="true">
22+
<div class="modal-dialog modal-lg">
23+
<div class="modal-content">
24+
<div class="modal-header">
25+
<h5 class="modal-title" id="issueModalLabel">Issue Details</h5>
26+
<button type="button" class="btn-close" data-bs-dismiss="modal" data-bs-theme="dark" aria-label="Close"></button>
27+
</div>
28+
<div class="modal-body" id="issueModalBody">
29+
<!-- Content will be inserted here dynamically -->
30+
</div>
31+
<div class="modal-footer">
32+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
33+
<a href="#" class="btn btn-primary" id="viewOnGithub" target="_blank">View on GitHub</a>
34+
</div>
35+
</div>
36+
</div>
37+
</div>

0 commit comments

Comments
 (0)