deduplication

This commit is contained in:
overcuriousity 2025-08-10 16:30:06 +02:00
parent 050774ad99
commit 9ce2098439
4 changed files with 10123 additions and 10098 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
// src/components/AIQueryInterface.astro // src/components/AIQueryInterface.astro
import { getToolsData } from '../utils/dataService.js'; import { getToolsData } from '../utils/dataService.js';
import { isToolHosted } from '../utils/toolHelpers.js';
const data = await getToolsData(); const data = await getToolsData();
const tools = data.tools; const tools = data.tools;

View File

@ -22,36 +22,26 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
<link rel="icon" type="image/x-icon" href="/favicon.ico"> <link rel="icon" type="image/x-icon" href="/favicon.ico">
<script> <script>
function createToolSlug(toolName) { // Import utility functions from shared client module instead of duplicating
if (!toolName || typeof toolName !== 'string') { async function loadUtilityFunctions() {
console.warn('[toolHelpers] Invalid toolName provided to createToolSlug:', toolName); try {
return ''; const { createToolSlug, findToolByIdentifier, isToolHosted } = await import('../utils/clientUtils.js');
// Make functions available globally for backward compatibility
(window as any).createToolSlug = createToolSlug;
(window as any).findToolByIdentifier = findToolByIdentifier;
(window as any).isToolHosted = isToolHosted;
} catch (error) {
console.error('Failed to load utility functions:', error);
// Minimal fallback for critical functionality only
(window as any).createToolSlug = (toolName: string) => {
if (!toolName || typeof toolName !== 'string') return '';
return toolName.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
};
} }
return toolName.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '') // Remove special characters
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/-+/g, '-') // Remove duplicate hyphens
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
} }
function findToolByIdentifier(tools, identifier) { function scrollToElement(element: Element | null, options = {}) {
if (!identifier || !Array.isArray(tools)) return undefined;
return tools.find(tool =>
tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase()
);
}
function isToolHosted(tool) {
return tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
}
function scrollToElement(element, options = {}) {
if (!element) return; if (!element) return;
setTimeout(() => { setTimeout(() => {
@ -67,17 +57,21 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
}, 100); }, 100);
} }
function scrollToElementById(elementId, options = {}) { function scrollToElementById(elementId: string, options = {}) {
const element = document.getElementById(elementId); const element = document.getElementById(elementId);
scrollToElement(element, options); if (element) {
scrollToElement(element, options);
}
} }
function scrollToElementBySelector(selector, options = {}) { function scrollToElementBySelector(selector: string, options = {}) {
const element = document.querySelector(selector); const element = document.querySelector(selector);
scrollToElement(element, options); if (element) {
scrollToElement(element, options);
}
} }
function prioritizeSearchResults(tools, searchTerm) { function prioritizeSearchResults(tools: any[], searchTerm: string) {
if (!searchTerm || !searchTerm.trim()) { if (!searchTerm || !searchTerm.trim()) {
return tools; return tools;
} }
@ -85,8 +79,8 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
const lowerSearchTerm = searchTerm.toLowerCase().trim(); const lowerSearchTerm = searchTerm.toLowerCase().trim();
return tools.sort((a, b) => { return tools.sort((a, b) => {
const aTagsLower = (a.tags || []).map(tag => tag.toLowerCase()); const aTagsLower = (a.tags || []).map((tag: string) => tag.toLowerCase());
const bTagsLower = (b.tags || []).map(tag => tag.toLowerCase()); const bTagsLower = (b.tags || []).map((tag: string) => tag.toLowerCase());
const aExactTag = aTagsLower.includes(lowerSearchTerm); const aExactTag = aTagsLower.includes(lowerSearchTerm);
const bExactTag = bTagsLower.includes(lowerSearchTerm); const bExactTag = bTagsLower.includes(lowerSearchTerm);
@ -98,15 +92,16 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
}); });
} }
(window as any).createToolSlug = createToolSlug; // Set non-duplicated functions on window
(window as any).findToolByIdentifier = findToolByIdentifier;
(window as any).isToolHosted = isToolHosted;
(window as any).scrollToElement = scrollToElement; (window as any).scrollToElement = scrollToElement;
(window as any).scrollToElementById = scrollToElementById; (window as any).scrollToElementById = scrollToElementById;
(window as any).scrollToElementBySelector = scrollToElementBySelector; (window as any).scrollToElementBySelector = scrollToElementBySelector;
(window as any).prioritizeSearchResults = prioritizeSearchResults; (window as any).prioritizeSearchResults = prioritizeSearchResults;
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// Load utility functions first
loadUtilityFunctions();
const THEME_KEY = 'dfir-theme'; const THEME_KEY = 'dfir-theme';
function getSystemTheme() { function getSystemTheme() {
@ -117,12 +112,12 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
return localStorage.getItem(THEME_KEY) || 'auto'; return localStorage.getItem(THEME_KEY) || 'auto';
} }
function applyTheme(theme) { function applyTheme(theme: string) {
const effectiveTheme = theme === 'auto' ? getSystemTheme() : theme; const effectiveTheme = theme === 'auto' ? getSystemTheme() : theme;
document.documentElement.setAttribute('data-theme', effectiveTheme); document.documentElement.setAttribute('data-theme', effectiveTheme);
} }
function updateThemeToggle(theme) { function updateThemeToggle(theme: string) {
document.querySelectorAll('[data-theme-toggle]').forEach(button => { document.querySelectorAll('[data-theme-toggle]').forEach(button => {
button.setAttribute('data-current-theme', theme); button.setAttribute('data-current-theme', theme);
}); });
@ -192,7 +187,7 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
} }
} }
async function requireClientAuth(callback, returnUrl, context = 'general') { async function requireClientAuth(callback: () => void, returnUrl: string, context = 'general') {
const authStatus = await checkClientAuth(context); const authStatus = await checkClientAuth(context);
if (authStatus.authRequired && !authStatus.authenticated) { if (authStatus.authRequired && !authStatus.authenticated) {
@ -207,12 +202,12 @@ const { title, description = 'ForensicPathways - A comprehensive directory of di
} }
} }
async function showIfAuthenticated(selector, context = 'general') { async function showIfAuthenticated(selector: string, context = 'general') {
const authStatus = await checkClientAuth(context); const authStatus = await checkClientAuth(context);
const element = document.querySelector(selector); const element = document.querySelector(selector);
if (element) { if (element) {
element.style.display = (!authStatus.authRequired || authStatus.authenticated) (element as HTMLElement).style.display = (!authStatus.authRequired || authStatus.authenticated)
? 'inline-flex' ? 'inline-flex'
: 'none'; : 'none';
} }

31
src/utils/clientUtils.ts Normal file
View File

@ -0,0 +1,31 @@
// src/utils/clientUtils.js
// Client-side utilities that mirror server-side toolHelpers.ts
export function createToolSlug(toolName) {
if (!toolName || typeof toolName !== 'string') {
console.warn('[toolHelpers] Invalid toolName provided to createToolSlug:', toolName);
return '';
}
return toolName.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '') // Remove special characters
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/-+/g, '-') // Remove duplicate hyphens
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
}
export function findToolByIdentifier(tools, identifier) {
if (!identifier || !Array.isArray(tools)) return undefined;
return tools.find(tool =>
tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase()
);
}
export function isToolHosted(tool) {
return tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
}