main #11
20110
data/embeddings.json
20110
data/embeddings.json
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||||
|
@ -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()
|
function scrollToElement(element: Element | null, options = {}) {
|
||||||
.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) {
|
|
||||||
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);
|
||||||
|
if (element) {
|
||||||
scrollToElement(element, options);
|
scrollToElement(element, options);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function scrollToElementBySelector(selector, options = {}) {
|
function scrollToElementBySelector(selector: string, options = {}) {
|
||||||
const element = document.querySelector(selector);
|
const element = document.querySelector(selector);
|
||||||
|
if (element) {
|
||||||
scrollToElement(element, options);
|
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
31
src/utils/clientUtils.ts
Normal 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() !== "";
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user