Skip to content

Commit 15d5c5b

Browse files
UI(fix) : Updates "Useful Devtools" webpage (#1460)
* Updated devtools webpage * Update pages/devtools.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update pages/devtools.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update pages/devtools.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update styles/devtools.css Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 75101a5 commit 15d5c5b

2 files changed

Lines changed: 778 additions & 100 deletions

File tree

pages/devtools.html

Lines changed: 198 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,71 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Awesome Developer Tools</title>
77
<link rel="icon" href="recode-hive.png">
8-
<script src="https://cdn.tailwindcss.com"></script>
8+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
99
<link rel="stylesheet" href="../styles/devtools.css" />
1010
</head>
11-
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col items-center">
12-
<header class="w-full bg-gradient-to-r from-blue-900 to-green-900 text-white text-center py-4 sm:py-6 lg:py-8 shadow-lg top-0">
13-
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold animate-pulse">Awesome Developer Tools</h1>
14-
<p class="mt-2 text-xs sm:text-sm md:text-base lg:text-lg max-w-2xl mx-auto">A curated, interactive, and responsive collection of tools to supercharge your development workflow.</p>
15-
<div class="mt-4 flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center items-center px-4">
16-
<input type="text" id="search" placeholder="Search by name, description, or category..." class="w-full sm:w-80 md:w-96 p-3 rounded-full bg-gray-800 text-gray-100 border-none focus:ring-2 focus:ring-blue-500 transition-all duration-300 text-sm sm:text-base">
17-
<div class="custom-select-wrapper">
18-
<select id="filter-select" class="w-full p-3 rounded-full bg-gray-800 text-gray-100 border-none focus:ring-2 focus:ring-blue-500 transition-all duration-300 text-sm sm:text-base">
19-
<option value="">All Categories</option>
20-
<!-- Categories populated by JS -->
21-
</select>
11+
<body>
12+
<header id="header">
13+
<div class="header-container">
14+
<div class="header-content">
15+
<h1>Awesome Developer Tools</h1>
16+
<p>A curated collection of tools to supercharge your development workflow.</p>
17+
</div>
18+
<div class="toggle-switch">
19+
<input type="checkbox" id="theme-toggle" aria-label="Toggle dark mode">
20+
<label for="theme-toggle">
21+
<div class="switch-button">
22+
<span class="material-icons sun-icon">wb_sunny</span>
23+
<span class="material-icons moon-icon">brightness_2</span>
24+
</div>
25+
</label>
2226
</div>
2327
</div>
2428
</header>
25-
<main class="w-full max-w-7xl px-4 sm:px-6 lg:px-8 py-8">
26-
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 sm:gap-6" id="tool-grid">
27-
<!-- Tools will be rendered here by JS -->
29+
30+
<main id="main">
31+
<div class="container">
32+
<!-- Search and Filter -->
33+
<div class="search-filter-container">
34+
<div class="search-wrapper">
35+
<input type="text" id="search" placeholder="Search tools..." class="search-input">
36+
<span class="search-icon material-icons">search</span>
37+
</div>
38+
39+
<select id="filter-select" class="filter-select">
40+
<option value="">All Categories</option>
41+
</select>
42+
43+
<button id="clear-filters" class="clear-filters-btn hidden">
44+
<span class="material-icons">close</span>
45+
Clear Filters
46+
</button>
47+
48+
<div class="view-toggle">
49+
<button id="grid-view-btn" class="view-btn active" title="Grid View" aria-label="Grid View">
50+
<span class="material-icons">dashboard</span>
51+
</button>
52+
<button id="list-view-btn" class="view-btn" title="List View" aria-label="List View">
53+
<span class="material-icons">menu</span>
54+
</button>
55+
</div>
56+
</div>
57+
58+
<!-- Results Info -->
59+
<div class="results-info">
60+
<span id="tool-count" class="tool-count-badge">Showing <strong>0</strong> tools</span>
61+
</div>
62+
63+
<!-- Tools Grid -->
64+
<div class="tool-grid" id="tool-grid">
65+
<!-- Tools will be rendered here by JS -->
66+
</div>
67+
68+
<div id="no-results" class="no-results hidden">
69+
<p>No tools found</p>
70+
</div>
2871
</div>
2972
</main>
30-
<button id="back-to-top" title="Back to Top" class="fixed bottom-4 sm:bottom-6 right-4 sm:right-6 bg-blue-900 text-white rounded-full w-10 h-10 sm:w-12 sm:h-12 flex items-center justify-center shadow-lg opacity-0 transition-all duration-300 hover:bg-blue-700 hover:scale-110 text-sm sm:text-base"></button>
3173
<script>
3274
// List of tools
3375
const tools = [
@@ -86,19 +128,61 @@ <h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold animate-pulse"
86128
filterSelect.appendChild(option);
87129
});
88130

131+
// Category colors for visual variety
132+
const categoryColors = {
133+
'Analytics Tools': 'from-purple-500/20 to-purple-600/20',
134+
'Cloud Platforms': 'from-blue-500/20 to-blue-600/20',
135+
'AI Coding Tools': 'from-pink-500/20 to-pink-600/20',
136+
'IDEs & Code Editors': 'from-orange-500/20 to-orange-600/20',
137+
'CLIs & Terminal Tools': 'from-green-500/20 to-green-600/20',
138+
'DevOps & Infrastructure': 'from-red-500/20 to-red-600/20'
139+
};
140+
141+
const categoryBadges = {
142+
'Analytics Tools': 'text-purple-400 bg-purple-500/20',
143+
'Cloud Platforms': 'text-blue-400 bg-blue-500/20',
144+
'AI Coding Tools': 'text-pink-400 bg-pink-500/20',
145+
'IDEs & Code Editors': 'text-orange-400 bg-orange-500/20',
146+
'CLIs & Terminal Tools': 'text-green-400 bg-green-500/20',
147+
'DevOps & Infrastructure': 'text-red-400 bg-red-500/20'
148+
};
149+
89150
// Function to render tools
90151
function renderTools(filteredTools) {
91152
const grid = document.getElementById('tool-grid');
92-
grid.innerHTML = ''; // Clear existing
153+
const noResults = document.getElementById('no-results');
154+
const toolCount = document.getElementById('tool-count');
155+
156+
// Update tool count
157+
if (filteredTools.length === 0) {
158+
toolCount.innerHTML = 'Showing <strong>0</strong> tools';
159+
} else {
160+
toolCount.innerHTML = `Showing <strong>${filteredTools.length}</strong> tools`;
161+
}
162+
163+
if (filteredTools.length === 0) {
164+
grid.innerHTML = '';
165+
noResults.classList.remove('hidden');
166+
return;
167+
}
168+
169+
noResults.classList.add('hidden');
170+
grid.innerHTML = '';
171+
93172
filteredTools.forEach((tool, index) => {
94173
const card = document.createElement('div');
95-
card.className = 'bg-gray-800 rounded-lg p-4 sm:p-6 shadow-xl hover:shadow-2xl hover:scale-105 transform transition-all duration-300 animate-slide-up shine-effect';
96-
card.style.animationDelay = `${index * 0.1}s`;
174+
card.className = 'tool-card';
175+
card.style.animationDelay = `${index * 0.05}s`;
176+
97177
card.innerHTML = `
98-
<span class="text-xs uppercase text-gray-500">${tool.category}</span>
99-
<h2 class="text-lg sm:text-xl font-semibold text-blue-400 mt-2">${tool.name}</h2>
100-
<p class="text-gray-300 mt-2 text-sm sm:text-base">${tool.description}</p>
101-
<a href="${tool.link}" target="_blank" class="inline-block mt-4 bg-green-800 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition-all duration-300 text-sm sm:text-base">Visit</a>
178+
<div class="tool-header">
179+
<div>
180+
<h2 class="tool-name">${tool.name}</h2>
181+
<p class="tool-category">${tool.category}</p>
182+
</div>
183+
</div>
184+
<p class="tool-description">${tool.description}</p>
185+
<a href="${tool.link}" target="_blank" rel="noopener noreferrer" class="tool-link">Visit</a>
102186
`;
103187
grid.appendChild(card);
104188
});
@@ -122,21 +206,102 @@ <h2 class="text-lg sm:text-xl font-semibold text-blue-400 mt-2">${tool.name}</h2
122206
tool.category.toLowerCase().includes(query))
123207
);
124208
renderTools(filtered);
209+
updateClearFiltersButton();
125210
}
126211

127-
// Back to Top button
128-
const backToTop = document.getElementById('back-to-top');
129-
window.addEventListener('scroll', () => {
130-
if (window.scrollY > 300) {
131-
backToTop.classList.remove('opacity-0');
212+
// Update clear filters button visibility
213+
function updateClearFiltersButton() {
214+
const query = searchInput.value.trim();
215+
const selectedCategory = filterSelect.value;
216+
const clearBtn = document.getElementById('clear-filters');
217+
if (query !== '' || selectedCategory !== '') {
218+
clearBtn.style.display = 'inline-block';
132219
} else {
133-
backToTop.classList.add('opacity-0');
220+
clearBtn.style.display = 'none';
134221
}
135-
});
222+
}
136223

137-
backToTop.addEventListener('click', () => {
138-
window.scrollTo({ top: 0, behavior: 'smooth' });
139-
});
224+
// Clear filters button functionality
225+
const clearFiltersBtn = document.getElementById('clear-filters');
226+
if (clearFiltersBtn) {
227+
clearFiltersBtn.addEventListener('click', () => {
228+
searchInput.value = '';
229+
filterSelect.value = '';
230+
renderTools(tools);
231+
updateClearFiltersButton();
232+
});
233+
}
234+
235+
// View toggle functionality
236+
const gridViewBtn = document.getElementById('grid-view-btn');
237+
const listViewBtn = document.getElementById('list-view-btn');
238+
const toolGrid = document.getElementById('tool-grid');
239+
240+
function setViewMode(mode) {
241+
if (mode === 'list') {
242+
toolGrid.classList.remove('grid-view');
243+
toolGrid.classList.add('list-view');
244+
listViewBtn.classList.add('active');
245+
gridViewBtn.classList.remove('active');
246+
} else {
247+
toolGrid.classList.remove('list-view');
248+
toolGrid.classList.add('grid-view');
249+
gridViewBtn.classList.add('active');
250+
listViewBtn.classList.remove('active');
251+
}
252+
localStorage.setItem('devtools-view-mode', mode);
253+
}
254+
255+
// Load saved view mode or default to grid
256+
const savedViewMode = localStorage.getItem('devtools-view-mode') || 'grid';
257+
setViewMode(savedViewMode);
258+
259+
// Add event listeners for view toggle buttons
260+
if (gridViewBtn) {
261+
gridViewBtn.addEventListener('click', () => setViewMode('grid'));
262+
}
263+
264+
if (listViewBtn) {
265+
listViewBtn.addEventListener('click', () => setViewMode('list'));
266+
}
267+
268+
// Dark Mode Toggle - Similar to index.html
269+
const themeToggleCheckbox = document.querySelector("#theme-toggle");
270+
271+
// Function to set the theme
272+
function setTheme(theme) {
273+
if (theme === "dark") {
274+
document.body.classList.add("dark-mode");
275+
if (themeToggleCheckbox) {
276+
themeToggleCheckbox.checked = true;
277+
}
278+
} else {
279+
document.body.classList.remove("dark-mode");
280+
if (themeToggleCheckbox) {
281+
themeToggleCheckbox.checked = false;
282+
}
283+
}
284+
localStorage.setItem("devtools-theme", theme);
285+
}
286+
287+
// Load the theme from localStorage or set it to the system default
288+
const savedTheme = localStorage.getItem("devtools-theme");
289+
const defaultTheme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? "dark" : "light";
290+
setTheme(savedTheme || defaultTheme);
291+
292+
// Add event listener to toggle checkbox
293+
if (themeToggleCheckbox) {
294+
themeToggleCheckbox.addEventListener("change", () => {
295+
const newTheme = themeToggleCheckbox.checked ? "dark" : "light";
296+
setTheme(newTheme);
297+
});
298+
}
140299
</script>
300+
</body>
301+
</html>
302+
<script>
303+
document.getElementById("dynamic-year").textContent = new Date().getFullYear();
304+
</script>
305+
141306
</body>
142307
</html>

0 commit comments

Comments
 (0)