added mark.js and now it looks and works even better

This commit is contained in:
Yeghro 2025-01-24 21:48:08 -08:00
parent e390d63ba4
commit 4a5bfedd1f
3 changed files with 209 additions and 68 deletions

View File

@ -49,6 +49,8 @@
<div id="resources-container"></div> <div id="resources-container"></div>
</main> </main>
</div> </div>
<!-- Add marked.js before your script -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="script.js"></script> <script src="script.js"></script>
</body> </body>
</html> </html>

246
script.js
View File

@ -201,6 +201,7 @@ function parseResources(content) {
if (line.startsWith('## ')) { if (line.startsWith('## ')) {
currentMainSection = line.slice(3).trim(); currentMainSection = line.slice(3).trim();
currentSubSection = ''; currentSubSection = '';
console.log('Processing section:', currentMainSection); // Debug log
} else if (currentMainSection.toLowerCase() === 'contributors') { } else if (currentMainSection.toLowerCase() === 'contributors') {
const match = line.match(repoRegex); const match = line.match(repoRegex);
if (match) { if (match) {
@ -228,9 +229,13 @@ function parseResources(content) {
.replace(/[^a-z0-9]+/g, '-') .replace(/[^a-z0-9]+/g, '-')
.replace(/(^-|-$)/g, ''); .replace(/(^-|-$)/g, '');
console.log('Parsed resource:', categoryId, resource); // Debug log
// Add resource to appropriate category if it exists // Add resource to appropriate category if it exists
if (resources[categoryId]) { if (resources[categoryId]) {
resources[categoryId].push(resource); resources[categoryId].push(resource);
} else {
console.warn('Category not found:', categoryId); // Debug log
} }
} }
} }
@ -254,29 +259,33 @@ function parseResources(content) {
// Function to parse a single resource line // Function to parse a single resource line
function parseResourceLine(line) { function parseResourceLine(line) {
// Regular expressions to extract information // Updated regex patterns to better handle various markdown formats
const nameRegex = /\[(.*?)\]/; const nameRegex = /\[(.*?)\]/;
const linkRegex = /\((.*?)\)/; const linkRegex = /\((.*?)\)/;
const starsRegex = /!\[stars\].*?stars\/(.*?)\/.*?style=social/; const starsRegex = /!\[stars\].*?stars\/(.*?)\/.*?style=social/;
const descriptionRegex = /\) - (.*?)(?=\[|$)/; // Updated description regex to handle descriptions after stars badge
const descriptionRegex = /style=social\) - (.*?)(?=(?:\[|\n|$))|(?:\) - )(.*?)(?=(?:\[|\n|$))/;
try { try {
const name = nameRegex.exec(line)?.[1]; const name = nameRegex.exec(line)?.[1];
const link = linkRegex.exec(line)?.[1]; const link = linkRegex.exec(line)?.[1];
const stars = starsRegex.exec(line)?.[1]; const stars = starsRegex.exec(line)?.[1];
const description = descriptionRegex.exec(line)?.[1]?.trim();
if (name && (link || description)) { // More robust description extraction
const descMatch = descriptionRegex.exec(line);
const description = (descMatch?.[1] || descMatch?.[2] || '').trim();
if (name && link) {
return { return {
name, name,
link, link,
stars: stars || 0, stars: stars || 0,
description: description || '', description: description || '',
raw: line.trim() // Keep the original markdown line raw: line.trim()
}; };
} }
} catch (error) { } catch (error) {
console.error('Error parsing resource line:', error); console.error('Error parsing resource line:', error, line);
} }
return null; return null;
} }
@ -287,7 +296,6 @@ function createResourceCard(resource) {
card.className = 'resource-card'; card.className = 'resource-card';
card.dataset.stars = resource.stars || 0; card.dataset.stars = resource.stars || 0;
// Create a formatted version of the markdown content
const formattedContent = ` const formattedContent = `
<div class="resource-title"><strong>${resource.name}</strong></div> <div class="resource-title"><strong>${resource.name}</strong></div>
${resource.link ? ` ${resource.link ? `
@ -421,74 +429,194 @@ function getCategoryIcon(category) {
} }
// Function to generate navigation from content // Function to generate navigation from content
function generateNavigation(content) { function generateNavigation(sectionNames) {
const navList = document.querySelector('.nav-links'); const navList = document.querySelector('.nav-links');
const categories = []; navList.innerHTML = ''; // Clear existing navigation
let currentCategory = '';
// Split content by lines and find all ## headers sectionNames.forEach(section => {
const lines = content.split('\n'); // Create URL-friendly ID
lines.forEach(line => { const sectionId = section
if (line.startsWith('## ')) { .toLowerCase()
currentCategory = line.slice(3).trim(); .replace(/[^a-z0-9]+/g, '-')
const categoryId = currentCategory.toLowerCase().replace(/[^a-z0-9]+/g, '-'); .replace(/(^-|-$)/g, '');
const icon = getCategoryIcon(currentCategory.toLowerCase());
categories.push({ const li = document.createElement('li');
id: categoryId, li.innerHTML = `
name: currentCategory, <a href="#${sectionId}" data-section="${section}">
icon: icon <i class="fas fa-chevron-right"></i>
}); ${section}
}
});
// Generate navigation HTML
navList.innerHTML = categories.map(category => `
<li>
<a href="#${category.id}">
<i class="fas ${category.icon}"></i>
${category.name}
</a> </a>
</li> `;
`).join('');
// Add click event listeners to the new navigation items // Add click handler
document.querySelectorAll('.nav-links a').forEach(link => { li.querySelector('a').addEventListener('click', (e) => {
link.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
const categoryId = e.target.getAttribute('href').replace('#', ''); // Remove active class from all links
populateResources(categoryId, window.parsedResources); document.querySelectorAll('.nav-links a').forEach(a =>
a.classList.remove('active')
);
// Add active class to clicked link
e.target.classList.add('active');
// Display the section
displaySection(section, window.parsedResources);
}); });
navList.appendChild(li);
}); });
return categories; // Set first item as active
const firstLink = navList.querySelector('a');
if (firstLink) {
firstLink.classList.add('active');
}
} }
// Update the fetch call to generate navigation // Remove the old fetch call and replace with this initialization
fetch('./README.md') document.addEventListener('DOMContentLoaded', () => {
.then(response => { // Test if marked is loaded
if (typeof marked === 'undefined') {
console.error('marked.js is not loaded!');
document.getElementById('resources-container').innerHTML = `
<div class="error-message">
Error: marked.js library is not loaded properly.
</div>`;
return;
}
// Test marked with a simple markdown string
console.log('marked.js test:', marked.parse('# Test\nThis is a *test* of **marked.js**'));
// If everything is working, proceed with main functionality
parseAndDisplayContent()
.then(() => console.log('Content successfully parsed and displayed'))
.catch(error => {
console.error('Error in main content processing:', error);
document.getElementById('resources-container').innerHTML = `
<div class="error-message">
Error loading content: ${error.message}
</div>`;
});
});
async function parseAndDisplayContent() {
try {
const response = await fetch('./README.md');
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
return response.text(); const content = await response.text();
})
.then(content => {
console.log('README content loaded:', content.substring(0, 200) + '...');
// Generate navigation first // Parse the markdown into HTML
const categories = generateNavigation(content); const htmlContent = marked.parse(content);
// Then parse and populate resources // Create a temporary element to parse the HTML
window.parsedResources = parseResources(content); const tempDiv = document.createElement('div');
console.log('Parsed resources:', window.parsedResources); tempDiv.innerHTML = htmlContent;
// Load initial category (first one in the list) // Get all sections (h2 headers and their content)
if (categories.length > 0) { const sections = {};
populateResources(categories[0].id, window.parsedResources); let currentSection = null;
let currentSectionContent = [];
Array.from(tempDiv.children).forEach(element => {
if (element.tagName === 'H2') {
// If we have a previous section, save it
if (currentSection) {
sections[currentSection] = currentSectionContent;
}
// Start new section
currentSection = element.textContent.trim();
currentSectionContent = [];
} else if (currentSection) {
currentSectionContent.push({
type: element.tagName === 'UL' ? 'resources' : 'content',
element: element
});
}
});
// Save the last section
if (currentSection) {
sections[currentSection] = currentSectionContent;
}
// Store sections globally
window.parsedResources = sections;
// Generate navigation
const sectionNames = Object.keys(sections);
generateNavigation(sectionNames);
// Display initial section
if (sectionNames.length > 0) {
displaySection(sectionNames[0], sections);
}
} catch (error) {
console.error('Error processing markdown:', error);
throw error; // Re-throw to be caught by the main error handler
}
}
function displaySection(sectionName, sections) {
const container = document.getElementById('resources-container');
container.innerHTML = '';
// Add section header
const header = document.createElement('h2');
header.textContent = sectionName;
container.appendChild(header);
// Display section content
sections[sectionName].forEach(item => {
if (item.type === 'content') {
// Regular markdown content
const contentDiv = document.createElement('div');
contentDiv.className = 'markdown-content';
contentDiv.innerHTML = item.element.outerHTML;
container.appendChild(contentDiv);
} else if (item.type === 'resources') {
// Resource list
Array.from(item.element.children).forEach(li => {
const card = createResourceCard({
name: li.querySelector('a')?.textContent || '',
link: li.querySelector('a')?.href || '',
description: li.textContent.split('- ')[1]?.trim() || '',
stars: li.querySelector('img[alt="stars"]')
? parseInt(li.querySelector('img[alt="stars"]').src.match(/stars\/(\d+)/)?.[1]) || 0
: 0
});
container.appendChild(card);
});
} }
})
.catch(error => {
console.error('Error loading README:', error);
document.getElementById('resources-container').innerHTML =
`<div class="error-message">Error loading resources: ${error.message}</div>`;
}); });
}
function createResourceCard(resource) {
const card = document.createElement('div');
card.className = 'resource-card';
card.innerHTML = `
<div class="resource-header">
<h3 class="resource-title">
<a href="${resource.link}" target="_blank">
${resource.name}
<i class="fas fa-external-link-alt"></i>
</a>
</h3>
${resource.stars ? `
<div class="resource-stars">
<i class="fas fa-star"></i>
${resource.stars}
</div>
` : ''}
</div>
${resource.description ? `
<div class="resource-description">
${resource.description}
</div>
` : ''}
`;
return card;
}

View File

@ -146,7 +146,7 @@ body {
} }
.resource-link a { .resource-link a {
color: var(--link-color); color: var(--primary-color);
text-decoration: none; text-decoration: none;
display: flex; display: flex;
align-items: center; align-items: center;
@ -159,12 +159,14 @@ body {
} }
.resource-description { .resource-description {
color: var(--text-secondary); color: var(--text-color);
margin-bottom: 12px; margin: 12px 0;
line-height: 1.5; line-height: 1.5;
font-size: 0.95em; font-size: 0.95em;
padding-left: 8px; padding: 8px 12px;
border-left: 3px solid var(--border-color); background: rgba(110, 84, 148, 0.05);
border-radius: 4px;
border-left: 3px solid var(--primary-color);
} }
.resource-stars { .resource-stars {
@ -313,3 +315,12 @@ body {
background-color: var(--primary-color); background-color: var(--primary-color);
color: white; color: white;
} }
.error-message {
padding: 1rem;
margin: 1rem;
background-color: #fff3f3;
border-left: 4px solid #ff4444;
color: #dc3545;
border-radius: 4px;
}