// Stack Router - Handles company and technology specific stack pages
class StackRouter {
constructor() {
this.routes = new Map();
this.currentRoute = null;
this.init();
}
init() {
// Listen for hash changes and initial load
window.addEventListener('hashchange', () => this.handleRouteChange());
window.addEventListener('load', () => this.handleRouteChange());
// Check for path-based routes on load
this.handleRouteChange();
}
// Get company info from data loader
getCompanyInfo(slug) {
return window.dataLoader.getCompanyInfo(slug);
}
// Get technology info from data loader
getTechnologyInfo(slug) {
return window.dataLoader.getTechnologyInfo(slug);
}
// Handle route changes
handleRouteChange() {
const path = window.location.pathname;
const hash = window.location.hash;
// Check for company routes (/company/epic-games)
const companyMatch = path.match(/\/company\/([^\/]+)/);
if (companyMatch) {
this.loadCompanyStack(companyMatch[1]);
return;
}
// Check for technology routes (/technology/unity)
const technologyMatch = path.match(/\/technology\/([^\/]+)/);
if (technologyMatch) {
this.loadTechnologyStack(technologyMatch[1]);
return;
}
// Check for hash-based routes for development
if (hash.startsWith('#/company/')) {
const company = hash.replace('#/company/', '');
this.loadCompanyStack(company);
return;
}
if (hash.startsWith('#/technology/')) {
const technology = hash.replace('#/technology/', '');
this.loadTechnologyStack(technology);
return;
}
if (hash === '#/companies') {
this.loadAllCompaniesPage();
return;
}
// Return to main page
this.loadMainPage();
}
// Load company-specific stack page
async loadCompanyStack(companySlug) {
const companyInfo = this.getCompanyInfo(companySlug);
if (!companyInfo) {
console.error('Company not found:', companySlug);
return;
}
this.currentRoute = { type: 'company', slug: companySlug, info: companyInfo };
// Wait for data to be loaded
if (!window.dataLoader.componentsData) {
await window.dataLoader.loadAllComponents();
}
// Get company stack components
const stackComponents = window.dataLoader.getCompanyStack(companySlug);
// Update page content
this.renderStackPage(companyInfo, stackComponents, 'company');
// Update page title and meta
document.title = `${companyInfo.name} Stack - Claude Code Templates`;
this.updateMetaTags(companyInfo, 'company');
}
// Load technology-specific stack page
async loadTechnologyStack(techSlug) {
const techInfo = this.getTechnologyInfo(techSlug);
if (!techInfo) {
console.error('Technology not found:', techSlug);
return;
}
this.currentRoute = { type: 'technology', slug: techSlug, info: techInfo };
// Wait for data to be loaded
if (!window.dataLoader.componentsData) {
await window.dataLoader.loadAllComponents();
}
// Get technology stack components
const stackComponents = window.dataLoader.getTechnologyStack(techSlug);
// Update page content
this.renderStackPage(techInfo, stackComponents, 'technology');
// Update page title and meta
document.title = `${techInfo.name} Stack - Claude Code Templates`;
this.updateMetaTags(techInfo, 'technology');
}
// Render stack page content
renderStackPage(stackInfo, components, type) {
const main = document.querySelector('main.terminal');
if (!main) return;
// Hide original content
const originalSections = main.querySelectorAll('section:not(.stack-page)');
originalSections.forEach(section => section.style.display = 'none');
// Remove existing stack page if any
const existingStackPage = main.querySelector('.stack-page');
if (existingStackPage) {
existingStackPage.remove();
}
// Create stack page
const stackPageHTML = this.generateStackPageHTML(stackInfo, components, type);
main.insertAdjacentHTML('afterbegin', stackPageHTML);
// Initialize cart functionality for the new page
if (window.initializeCartForStackPage) {
window.initializeCartForStackPage();
}
// Update header to show back button
this.updateHeaderForStack(stackInfo);
}
// Generate stack page HTML
generateStackPageHTML(stackInfo, components, type) {
const totalComponents = Object.values(components).reduce((sum, arr) => sum + arr.length, 0);
return `
${this.generateStackComponentsHTML(components)}
🚀 Install Complete ${stackInfo.name} Stack
Get all ${totalComponents} components with a single command:
$
${this.generateStackInstallCommand(components)}
Copy
`;
}
// Generate components sections HTML
generateStackComponentsHTML(components) {
let html = '';
const sections = [
{ type: 'agents', title: 'AI Agents', icon: '🤖', description: 'Specialized AI assistants for your workflow' },
{ type: 'commands', title: 'Commands', icon: '⚡', description: 'Ready-to-use automation commands' },
{ type: 'mcps', title: 'MCPs', icon: '🔌', description: 'Model Context Protocol integrations' }
];
sections.forEach(section => {
const items = components[section.type] || [];
if (items.length > 0) {
html += `
${items.map(component => this.generateComponentCardHTML(component)).join('')}
`;
}
});
return html;
}
// Generate component card HTML
generateComponentCardHTML(component) {
const { tags, companies, technologies } = window.dataLoader.getComponentMetadata(component.name);
return `
${this.extractDescription(component.content)}
${tags.length > 0 || technologies.length > 0 ? `
${[...tags.slice(0, 3), ...technologies.slice(0, 2)].map(tag =>
`${tag} `
).join('')}
` : ''}
`;
}
// Extract description from component content
extractDescription(content) {
const descMatch = content.match(/description:\s*(.+?)(?:\n|$)/);
if (descMatch) {
return descMatch[1].replace(/^['"]|['"]$/g, '').substring(0, 150) + '...';
}
return 'No description available';
}
// Generate install command for entire stack
generateStackInstallCommand(components) {
const allComponents = [...components.agents, ...components.commands, ...components.mcps];
const componentArgs = allComponents.map(c => `--${c.type} ${c.name}`).join(' ');
return `npx claude-code-templates@latest ${componentArgs}`;
}
// Update header for stack page
updateHeaderForStack(stackInfo) {
const header = document.querySelector('.header');
if (!header) return;
// Add back button
let backButton = header.querySelector('.back-button');
if (!backButton) {
backButton = document.createElement('button');
backButton.className = 'back-button';
backButton.innerHTML = `
Back to Main
`;
backButton.onclick = () => this.goBack();
const headerContent = header.querySelector('.header-content');
if (headerContent) {
headerContent.insertBefore(backButton, headerContent.firstChild);
}
}
}
// Update meta tags for SEO
updateMetaTags(stackInfo, type) {
// Update Open Graph tags
const ogTitle = document.querySelector('meta[property="og:title"]');
const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogTitle) {
ogTitle.content = `${stackInfo.name} Development Stack - Claude Code Templates`;
}
if (ogDescription) {
ogDescription.content = stackInfo.description;
}
// Update Twitter tags
const twitterTitle = document.querySelector('meta[name="twitter:title"]');
const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterTitle) {
twitterTitle.content = `${stackInfo.name} Development Stack - Claude Code Templates`;
}
if (twitterDescription) {
twitterDescription.content = stackInfo.description;
}
}
// Navigate back to main page
goBack() {
// Remove stack page
const stackPage = document.querySelector('.stack-page');
if (stackPage) {
stackPage.remove();
}
// Show original content
const main = document.querySelector('main.terminal');
if (main) {
const originalSections = main.querySelectorAll('section:not(.stack-page)');
originalSections.forEach(section => section.style.display = '');
}
// Remove back button
const backButton = document.querySelector('.back-button');
if (backButton) {
backButton.remove();
}
// Reset route
this.currentRoute = null;
window.history.pushState({}, '', window.location.pathname);
// Reset page title and meta
document.title = 'Claude Code Templates';
this.resetMetaTags();
}
// Load main page (reset everything)
loadMainPage() {
if (this.currentRoute) {
this.goBack();
}
}
// Reset meta tags to original values
resetMetaTags() {
const ogTitle = document.querySelector('meta[property="og:title"]');
const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogTitle) {
ogTitle.content = 'Claude Code Templates - Ready-to-use configurations';
}
if (ogDescription) {
ogDescription.content = 'Browse and install Claude Code configuration templates for different languages and frameworks. Includes 100+ agents, 159+ commands, 23+ MCPs, and 14+ templates.';
}
}
// Load all companies page
async loadAllCompaniesPage() {
this.currentRoute = { type: 'companies', slug: 'all' };
// Wait for data to be loaded
if (!window.dataLoader.componentsData) {
await window.dataLoader.loadAllComponents();
}
// Update page content
this.renderAllCompaniesPage();
// Update page title and meta
document.title = 'All Development Stacks - Claude Code Templates';
this.updateMetaTagsForAllCompanies();
}
// Render all companies page
renderAllCompaniesPage() {
const main = document.querySelector('main.terminal');
if (!main) return;
// Hide original content
const originalSections = main.querySelectorAll('section:not(.stack-page)');
originalSections.forEach(section => section.style.display = 'none');
// Remove existing stack page if any
const existingStackPage = main.querySelector('.stack-page');
if (existingStackPage) {
existingStackPage.remove();
}
// Get all companies from metadata
const allCompanies = window.dataLoader.metadataData?.companies || {};
// Create all companies page
const allCompaniesHTML = this.generateAllCompaniesPageHTML(allCompanies);
main.insertAdjacentHTML('afterbegin', allCompaniesHTML);
// Update header to show back button
this.updateHeaderForStack({ name: 'All Development Stacks' });
}
// Generate all companies page HTML
generateAllCompaniesPageHTML(companies) {
const companiesArray = Object.entries(companies);
// Group companies by category
const categories = {
'AI & Machine Learning': ['openai', 'anthropic'],
'Payments & E-commerce': ['stripe', 'shopify', 'shopify'],
'CRM & Business': ['salesforce', 'hubspot', 'airtable', 'linear'],
'Communication': ['twilio', 'slack', 'discord', 'sendgrid'],
'Cloud & Infrastructure': ['aws', 'vercel', 'netlify', 'cloudflare', 'firebase', 'supabase'],
'Databases': ['mongodb', 'planetscale'],
'Development Tools': ['github', 'figma', 'adobe', 'atlassian', 'notion'],
'Entertainment & Media': ['spotify', 'youtube', 'twitter'],
'Game Development': ['unity-technologies', 'epic-games'],
'Marketing': ['mailchimp', 'hubspot']
};
let categorizedHTML = '';
let uncategorizedCompanies = [...companiesArray];
// Generate categorized sections
Object.entries(categories).forEach(([categoryName, companyIds]) => {
const categoryCompanies = companyIds
.map(id => companiesArray.find(([key]) => key === id))
.filter(Boolean);
if (categoryCompanies.length > 0) {
categorizedHTML += `
${categoryName}
${categoryCompanies.map(([key, company]) => {
// Remove from uncategorized list
uncategorizedCompanies = uncategorizedCompanies.filter(([k]) => k !== key);
return this.generateCompanyCardHTML(key, company);
}).join('')}
`;
}
});
// Add uncategorized companies if any
if (uncategorizedCompanies.length > 0) {
categorizedHTML += `
Other Platforms
${uncategorizedCompanies.map(([key, company]) =>
this.generateCompanyCardHTML(key, company)
).join('')}
`;
}
return `
`;
}
// Generate individual company card for all companies page
generateCompanyCardHTML(companyKey, company) {
return `
${company.logo}
${company.name}
${company.description}
→
`;
}
// Update meta tags for all companies page
updateMetaTagsForAllCompanies() {
const ogTitle = document.querySelector('meta[property="og:title"]');
const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogTitle) {
ogTitle.content = 'All Development Stacks - Claude Code Templates';
}
if (ogDescription) {
ogDescription.content = 'Browse all available development stacks for major companies and platforms. Find agents, commands, and MCPs for APIs like OpenAI, Stripe, Shopify, AWS, and more.';
}
}
// Navigate programmatically
navigateTo(path) {
window.history.pushState({}, '', path);
this.handleRouteChange();
}
}
// Initialize router when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.stackRouter = new StackRouter();
});
// Make it available globally
window.StackRouter = StackRouter;