progress
This commit is contained in:
		
							parent
							
								
									921abfb5b9
								
							
						
					
					
						commit
						47eb5ad72a
					
				
							
								
								
									
										21
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										21
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -8,9 +8,11 @@
 | 
			
		||||
      "name": "dfir-tools-hub",
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "astro": "^4.0.0"
 | 
			
		||||
        "astro": "^4.0.0",
 | 
			
		||||
        "js-yaml": "^4.1.0"
 | 
			
		||||
      },
 | 
			
		||||
      "devDependencies": {
 | 
			
		||||
        "@types/node": "^24.0.13",
 | 
			
		||||
        "terser": "^5.27.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
@ -1673,6 +1675,16 @@
 | 
			
		||||
        "@types/unist": "*"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@types/node": {
 | 
			
		||||
      "version": "24.0.13",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz",
 | 
			
		||||
      "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==",
 | 
			
		||||
      "devOptional": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "undici-types": "~7.8.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@types/unist": {
 | 
			
		||||
      "version": "3.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
 | 
			
		||||
@ -5044,6 +5056,13 @@
 | 
			
		||||
        "node": ">=14.17"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/undici-types": {
 | 
			
		||||
      "version": "7.8.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
 | 
			
		||||
      "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
 | 
			
		||||
      "devOptional": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/unified": {
 | 
			
		||||
      "version": "11.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
 | 
			
		||||
 | 
			
		||||
@ -11,12 +11,14 @@
 | 
			
		||||
    "astro": "astro"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "astro": "^4.0.0"
 | 
			
		||||
    "astro": "^4.0.0",
 | 
			
		||||
    "js-yaml": "^4.1.0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/node": "^24.0.13",
 | 
			
		||||
    "terser": "^5.27.0"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=18.0.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
<button 
 | 
			
		||||
  class="btn-icon" 
 | 
			
		||||
  data-theme-toggle
 | 
			
		||||
  data-current-theme="auto"
 | 
			
		||||
  onclick="window.themeUtils.toggleTheme()"
 | 
			
		||||
  title="Toggle theme"
 | 
			
		||||
>
 | 
			
		||||
@ -39,12 +40,26 @@
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  /* Default to auto icon if no attribute is set */
 | 
			
		||||
  [data-theme-toggle] .theme-icon-auto {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  [data-current-theme="light"] .theme-icon-light,
 | 
			
		||||
  [data-current-theme="dark"] .theme-icon-dark,
 | 
			
		||||
  [data-current-theme="auto"] .theme-icon-auto {
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  [data-current-theme="light"] .theme-icon-dark,
 | 
			
		||||
  [data-current-theme="light"] .theme-icon-auto,
 | 
			
		||||
  [data-current-theme="dark"] .theme-icon-light,
 | 
			
		||||
  [data-current-theme="dark"] .theme-icon-auto,
 | 
			
		||||
  [data-current-theme="auto"] .theme-icon-light,
 | 
			
		||||
  [data-current-theme="auto"] .theme-icon-dark {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  [data-current-theme="auto"] path {
 | 
			
		||||
    fill: currentColor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								src/env.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								src/env.d.ts
									
									
									
									
										vendored
									
									
								
							@ -1 +1,28 @@
 | 
			
		||||
/// <reference path="../.astro/types.d.ts" />
 | 
			
		||||
/// <reference path="../.astro/types.d.ts" />
 | 
			
		||||
 | 
			
		||||
// Extend the Window interface to include custom properties
 | 
			
		||||
declare global {
 | 
			
		||||
  interface Window {
 | 
			
		||||
    themeUtils: {
 | 
			
		||||
      initTheme: () => void;
 | 
			
		||||
      toggleTheme: () => void;
 | 
			
		||||
      getStoredTheme: () => string;
 | 
			
		||||
    };
 | 
			
		||||
    toolsData: any[];
 | 
			
		||||
    showToolDetails: (toolName: string) => void;
 | 
			
		||||
    hideToolDetails: () => void;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Custom event types
 | 
			
		||||
  interface WindowEventMap {
 | 
			
		||||
    'toolsFiltered': CustomEvent<any[]>;
 | 
			
		||||
    'viewChanged': CustomEvent<string>;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Also declare the modules that might not be recognized
 | 
			
		||||
declare module 'js-yaml' {
 | 
			
		||||
  export function load(str: string): any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {};
 | 
			
		||||
@ -22,7 +22,7 @@ const { title, description = 'DFIR Tools Hub - A comprehensive directory of digi
 | 
			
		||||
  <script src="/src/scripts/theme.js"></script>
 | 
			
		||||
  <script>
 | 
			
		||||
    // Initialize theme immediately to prevent flash
 | 
			
		||||
    window.themeUtils.initTheme();
 | 
			
		||||
    (window as any).themeUtils?.initTheme();
 | 
			
		||||
  </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
@ -54,12 +54,19 @@ const tools = data.tools;
 | 
			
		||||
    const matrixContainer = document.getElementById('matrix-container');
 | 
			
		||||
    const noResults = document.getElementById('no-results');
 | 
			
		||||
    
 | 
			
		||||
    // Guard against null elements
 | 
			
		||||
    if (!toolsContainer || !toolsGrid || !matrixContainer || !noResults) {
 | 
			
		||||
      console.error('Required DOM elements not found');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Initial tools HTML
 | 
			
		||||
    const initialToolsHTML = toolsContainer.innerHTML;
 | 
			
		||||
    
 | 
			
		||||
    // Handle filtered results
 | 
			
		||||
    window.addEventListener('toolsFiltered', (event) => {
 | 
			
		||||
      const filtered = event.detail;
 | 
			
		||||
    window.addEventListener('toolsFiltered', (event: Event) => {
 | 
			
		||||
      const customEvent = event as CustomEvent;
 | 
			
		||||
      const filtered = customEvent.detail;
 | 
			
		||||
      const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
 | 
			
		||||
      
 | 
			
		||||
      if (currentView === 'matrix') {
 | 
			
		||||
@ -76,7 +83,7 @@ const tools = data.tools;
 | 
			
		||||
        noResults.style.display = 'none';
 | 
			
		||||
        
 | 
			
		||||
        // Render filtered tools
 | 
			
		||||
        filtered.forEach(tool => {
 | 
			
		||||
        filtered.forEach((tool: any) => {
 | 
			
		||||
          const toolCard = createToolCard(tool);
 | 
			
		||||
          toolsContainer.appendChild(toolCard);
 | 
			
		||||
        });
 | 
			
		||||
@ -84,8 +91,9 @@ const tools = data.tools;
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Handle view changes
 | 
			
		||||
    window.addEventListener('viewChanged', (event) => {
 | 
			
		||||
      const view = event.detail;
 | 
			
		||||
    window.addEventListener('viewChanged', (event: Event) => {
 | 
			
		||||
      const customEvent = event as CustomEvent;
 | 
			
		||||
      const view = customEvent.detail;
 | 
			
		||||
      
 | 
			
		||||
      if (view === 'matrix') {
 | 
			
		||||
        toolsGrid.style.display = 'none';
 | 
			
		||||
@ -97,7 +105,7 @@ const tools = data.tools;
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Create tool card element
 | 
			
		||||
    function createToolCard(tool) {
 | 
			
		||||
    function createToolCard(tool: any): HTMLElement {
 | 
			
		||||
      const cardDiv = document.createElement('div');
 | 
			
		||||
      const cardClass = tool.isHosted ? 'card card-hosted' : (tool.license !== 'Proprietary' ? 'card card-oss' : 'card');
 | 
			
		||||
      cardDiv.className = cardClass;
 | 
			
		||||
@ -149,7 +157,7 @@ const tools = data.tools;
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div style="display: flex; flex-wrap: wrap; gap: 0.25rem; margin-bottom: 1rem;">
 | 
			
		||||
          ${tool.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
 | 
			
		||||
          ${tool.tags.map((tag: string) => `<span class="tag">${tag}</span>`).join('')}
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary" style="width: 100%;">
 | 
			
		||||
 | 
			
		||||
@ -17,15 +17,20 @@ function applyTheme(theme) {
 | 
			
		||||
  document.documentElement.setAttribute('data-theme', effectiveTheme);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update theme toggle button state
 | 
			
		||||
function updateThemeToggle(theme) {
 | 
			
		||||
  document.querySelectorAll('[data-theme-toggle]').forEach(button => {
 | 
			
		||||
    button.setAttribute('data-current-theme', theme);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Initialize theme on page load
 | 
			
		||||
function initTheme() {
 | 
			
		||||
  const storedTheme = getStoredTheme();
 | 
			
		||||
  applyTheme(storedTheme);
 | 
			
		||||
  
 | 
			
		||||
  // Update theme toggle buttons
 | 
			
		||||
  document.querySelectorAll('[data-theme-toggle]').forEach(button => {
 | 
			
		||||
    button.setAttribute('data-current-theme', storedTheme);
 | 
			
		||||
  });
 | 
			
		||||
  // Update theme toggle buttons immediately
 | 
			
		||||
  updateThemeToggle(storedTheme);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle theme toggle
 | 
			
		||||
@ -38,11 +43,7 @@ function toggleTheme() {
 | 
			
		||||
  
 | 
			
		||||
  localStorage.setItem(THEME_KEY, nextTheme);
 | 
			
		||||
  applyTheme(nextTheme);
 | 
			
		||||
  
 | 
			
		||||
  // Update all theme toggle buttons
 | 
			
		||||
  document.querySelectorAll('[data-theme-toggle]').forEach(button => {
 | 
			
		||||
    button.setAttribute('data-current-theme', nextTheme);
 | 
			
		||||
  });
 | 
			
		||||
  updateThemeToggle(nextTheme);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Listen for system theme changes
 | 
			
		||||
@ -52,6 +53,12 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ()
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Initialize immediately when script loads
 | 
			
		||||
initTheme();
 | 
			
		||||
 | 
			
		||||
// Also initialize when DOM is ready (for safety)
 | 
			
		||||
document.addEventListener('DOMContentLoaded', initTheme);
 | 
			
		||||
 | 
			
		||||
// Export functions for use in Astro components
 | 
			
		||||
window.themeUtils = {
 | 
			
		||||
  initTheme,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user