Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed app/assets/guitar/guitarLogo.png
Binary file not shown.
Binary file removed app/assets/guitar/guitarLogo_old.png
Binary file not shown.
75 changes: 58 additions & 17 deletions app/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -341,41 +341,82 @@ footer a:hover {
overflow: hidden;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.08);
display: flex;
flex-direction: column;
transition: box-shadow 0.2s;
}

.project-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}

.project-image {
width: 100%;
height: 160px;
object-fit: cover;
display: block;
.project-card-header {
padding: 1.25rem;
display: flex;
justify-content: space-between;
align-items: center;
}

.project-info {
padding: 1rem;
.project-card-title {
color: white;
font-size: 1.1rem;
font-weight: 600;
}

.project-info h3 {
margin: 0 0 0.5rem 0;
.project-card-lang {
color: rgba(255,255,255,0.8);
font-size: 0.8rem;
background: rgba(255,255,255,0.15);
padding: 0.2rem 0.5rem;
border-radius: 4px;
}

.project-info h3 a {
text-decoration: none;
color: inherit;
.project-card-body {
padding: 1rem 1.25rem;
flex: 1;
}

.project-card-desc {
color: #475569;
font-size: 0.95rem;
line-height: 1.6;
margin: 0 0 0.75rem 0;
}

.project-meta {
margin-top: 0.75rem;
.project-card-meta {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
gap: 1rem;
font-size: 0.8rem;
color: #94a3b8;
}

.project-card-footer {
padding: 0.75rem 1.25rem;
border-top: 1px solid #f0f0f0;
display: flex;
gap: 0.75rem;
}

.project-card-btn {
font-size: 0.85rem;
font-weight: 500;
text-decoration: none;
padding: 0.4rem 0.85rem;
border-radius: 4px;
border: 1px solid #0284c7;
color: #0284c7;
transition: opacity 0.2s;
}

.project-card-btn.primary {
background-color: #0284c7;
color: white;
}

.project-card-btn:hover {
opacity: 0.8;
}

/* Mobile: single column */
@media (max-width: 768px) {
.projects-grid {
grid-template-columns: 1fr;
Expand Down
73 changes: 30 additions & 43 deletions app/scripts/loaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { API_BASE } from "/scripts/api.js";
import { PROJECTS_CONFIG } from "/scripts/projects.config.js";

// ---------------------------------------------------------------------------
// Module-level cache — stores the Promise, not the result
Expand Down Expand Up @@ -198,67 +199,53 @@ async function loadHeaderData() {
}

// ---------------------------------------------------------------------------
// Projects — fetched from GitHub API, filtered by whitelist
// Projects — GitHub API, driven by projects.config.js
// ---------------------------------------------------------------------------

const GITHUB_USERNAME = "mr-flowjangles";

const ALLOWED_REPOS = [
"the-fret-detective",
"bot-factory-ui",
];

async function loadProjects(container) {
container.innerHTML = `<div class="loading">Loading projects...</div>`;

try {
const { github_username, repos } = PROJECTS_CONFIG;

const response = await fetch(
`https://api.github.com/users/${GITHUB_USERNAME}/repos?per_page=100`
`https://api.github.com/users/${github_username}/repos?per_page=100`
);
if (!response.ok) throw new Error("Failed to load GitHub repos");

const repos = await response.json();

const filtered = ALLOWED_REPOS.map((name) =>
repos.find((r) => r.name === name)
).filter(Boolean);
const githubRepos = await response.json();

if (filtered.length === 0) {
container.innerHTML = `<p>No projects found.</p>`;
return;
}
const cards = repos
.map((config) => {
const repo = githubRepos.find((r) => r.name === config.name);
if (!repo) return "";

const cards = filtered
.map((repo) => {
const imageUrl = `https://opengraph.github.com/repo/${GITHUB_USERNAME}/${repo.name}`;
const description = repo.description || "No description provided.";
const updated = new Date(repo.updated_at).toLocaleDateString("en-US", {
year: "numeric",
month: "short",
});
const stars = repo.stargazers_count;
const language = repo.language || "";

return `
<div class="project-card">
<a href="${repo.html_url}" target="_blank" rel="noopener noreferrer">
<img
class="project-image"
src="${imageUrl}"
alt="${repo.name} preview"
loading="lazy"
/>
</a>
<div class="project-info">
<h3>
<a href="${repo.html_url}" target="_blank" rel="noopener noreferrer">
${repo.name}
</a>
</h3>
<p class="description">${description}</p>
<div class="project-meta">
${language ? `<span class="skill-tag">${language}</span>` : ""}
${stars > 0 ? `<span class="skill-tag">⭐ ${stars}</span>` : ""}
<div class="project-card">
<div class="project-card-header" style="background-color: ${config.color};">
<span class="project-card-title">${config.label}</span>
${language ? `<span class="project-card-lang">${language}</span>` : ""}
</div>
<div class="project-card-body">
<p class="project-card-desc">${config.description}</p>
<div class="project-card-meta">
${stars > 0 ? `<span>⭐ ${stars}</span>` : ""}
<span>Updated ${updated}</span>
</div>
</div>
<div class="project-card-footer">
${config.url ? `<a class="project-card-btn primary" href="${config.url}" target="_blank" rel="noopener noreferrer">Visit Site</a>` : ""}
<a class="project-card-btn" href="${repo.html_url}" target="_blank" rel="noopener noreferrer">View on GitHub</a>
</div>
</div>
</div>
`;
`;
})
.join("");

Expand Down
32 changes: 32 additions & 0 deletions app/scripts/projects.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Projects Configuration
* Edit this file to update what shows on the Projects section.
*
* Fields:
* name — exact GitHub repo name (must match exactly)
* label — display name shown on the card
* description — your own description, shown instead of GitHub's
* color — header band color (use a hex code)
*/

export const PROJECTS_CONFIG = {
github_username: "mr-flowjangles",

repos: [
{
name: "the-fret-detective",
label: "The Fret Detective",
description: "AI Guitar Teacher, forked from bot-factory-ui.",
// color: "#0284c7",
color: "#0f172a",
url: "https://thefretdetective.com",
},
{
name: "bot-factory-ui",
label: "Bot Factory UI",
description:
"Forkable web package to integrate with a RAG chatbot. bot-factory coming soon.",
color: "#0f172a",
},
],
};