consolidation

This commit is contained in:
overcuriousity 2025-07-25 12:23:56 +02:00
parent 1e7c1a2468
commit b7fea4f31f
6 changed files with 138 additions and 51 deletions

View File

@ -1,4 +1,6 @@
---
import { createToolSlug } from '../utils/toolHelpers.js';
export interface Props {
toolName: string;
context: 'card' | 'modal-primary' | 'modal-secondary';
@ -7,12 +9,8 @@ export interface Props {
const { toolName, context, size = 'small' } = Astro.props;
// Create URL-safe slug from tool name
const toolSlug = 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
// AFTER: Single line with centralized function
const toolSlug = createToolSlug(toolName);
const iconSize = size === 'small' ? '14' : '16';
---

View File

@ -286,26 +286,12 @@ domains.forEach((domain: any) => {
// ===== SHARING FUNCTIONALITY =====
// Create tool slug from name (same logic as ShareButton.astro)
function createToolSlug(toolName) {
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
}
// Find tool by name or slug
function findTool(identifier) {
return toolsData.find(tool =>
tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase()
);
}
// REMOVED: createToolSlug function - now using window.createToolSlug
// REMOVED: findTool function - now using window.findToolByIdentifier
// Generate share URLs
function generateShareURL(toolName, view, modal = null) {
const toolSlug = createToolSlug(toolName);
const toolSlug = window.createToolSlug(toolName);
const baseUrl = window.location.origin + window.location.pathname;
const params = new URLSearchParams();
params.set('tool', toolSlug);
@ -517,10 +503,7 @@ domains.forEach((domain: any) => {
elements.description.textContent = tool.description;
// Badges
const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
const hasValidProjectUrl = window.isToolHosted(tool);
elements.badges.innerHTML = '';
if (isConcept) {
@ -645,7 +628,7 @@ domains.forEach((domain: any) => {
}
if (tool.knowledgebase === true) {
const kbId = tool.name.toLowerCase().replace(/\s+/g, '-');
const kbId = window.createToolSlug(tool.name);
linksHTML += `
<a href="/knowledgebase#kb-${kbId}" class="btn btn-secondary" style="width: 100%; margin-top: 0.5rem;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
@ -665,7 +648,7 @@ domains.forEach((domain: any) => {
// ===== POPULATE SHARE BUTTON =====
const shareButtonContainer = document.getElementById(`share-button-${modalType}`);
if (shareButtonContainer) {
const toolSlug = createToolSlug(tool.name);
const toolSlug = window.createToolSlug(tool.name);
shareButtonContainer.innerHTML = `
<button class="share-btn share-btn--medium"
data-tool-name="${tool.name}"
@ -822,10 +805,7 @@ domains.forEach((domain: any) => {
}
const isMethod = tool.type === 'method';
const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
const hasValidProjectUrl = window.isToolHosted(tool);
const domains = tool.domains || [];
const phases = tool.phases || [];

View File

@ -23,6 +23,9 @@ const { title, description = 'CC24-Guide - A comprehensive directory of digital
<!-- CONSOLIDATED: Load theme script -->
<script src="/src/scripts/theme.js"></script>
<!-- CONSOLIDATED: Load tool utilities -->
<script src="/src/scripts/tool-utils.js"></script>
<!-- CONSOLIDATED: Load client-side auth utilities -->
<script src="/src/scripts/client-auth.js"></script>

View File

@ -217,22 +217,8 @@ const tools = data.tools;
checkboxWrappers.forEach(wrapper => wrapper.style.display = 'flex');
}
// Create tool slug from name
function createToolSlug(toolName) {
return toolName.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
}
// Find tool by name or slug
function findTool(identifier) {
return window.toolsData.find(tool =>
tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase()
);
}
// REMOVED: createToolSlug function - now using window.createToolSlug
// REMOVED: findTool function - now using window.findToolByIdentifier
// Navigation functions for sharing
window.navigateToGrid = function(toolName) {
@ -337,8 +323,8 @@ const tools = data.tools;
return;
}
// Find the tool by name or slug
const tool = findTool(toolParam);
// Find the tool by name or slug using global function
const tool = window.findToolByIdentifier(window.toolsData, toolParam);
if (!tool) {
console.warn('Shared tool not found:', toolParam);
return;

52
src/scripts/tool-utils.ts Normal file
View File

@ -0,0 +1,52 @@
// Client-side tool utilities
// Mirrors server-side function logic for consistency
/**
* Creates a URL-safe slug from a tool name (client-side version)
*/
function createToolSlug(toolName) {
if (!toolName || typeof toolName !== 'string') {
console.warn('[toolUtils] Invalid toolName provided:', 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
}
/**
* Finds a tool by name or slug from tools array (client-side version)
*/
function findToolByIdentifier(tools, identifier) {
if (!identifier || !Array.isArray(tools)) return undefined;
return tools.find(tool =>
tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase()
);
}
/**
* Checks if tool has a valid project URL (hosted on CC24 server)
*/
function isToolHosted(tool) {
return tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
}
// Make functions available globally for existing code compatibility
window.createToolSlug = createToolSlug;
window.findToolByIdentifier = findToolByIdentifier;
window.isToolHosted = isToolHosted;
// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
module.exports = { createToolSlug, findToolByIdentifier, isToolHosted };
}
console.log('Tool utilities loaded');

68
src/utils/toolHelpers.ts Normal file
View File

@ -0,0 +1,68 @@
/**
* Tool utility functions for consistent tool operations across the app
*/
export interface Tool {
name: string;
type?: 'software' | 'method' | 'concept';
projectUrl?: string | null;
license?: string;
knowledgebase?: boolean;
domains?: string[];
phases?: string[];
platforms?: string[];
skillLevel?: string;
description?: string;
tags?: string[];
related_concepts?: string[];
}
/**
* Creates a URL-safe slug from a tool name
* Used for URLs, IDs, and file names consistently across the app
*/
export function createToolSlug(toolName: string): string {
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
}
/**
* Finds a tool by name or slug from tools array
*/
export function findToolByIdentifier(tools: Tool[], identifier: string): Tool | undefined {
if (!identifier || !Array.isArray(tools)) return undefined;
return tools.find(tool =>
tool.name === identifier ||
createToolSlug(tool.name) === identifier.toLowerCase()
);
}
/**
* Checks if tool has a valid project URL (hosted on CC24 server)
*/
export function isToolHosted(tool: Tool): boolean {
return tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
}
/**
* Determines tool category for styling/logic
*/
export function getToolCategory(tool: Tool): 'concept' | 'method' | 'hosted' | 'oss' | 'proprietary' {
if (tool.type === 'concept') return 'concept';
if (tool.type === 'method') return 'method';
if (isToolHosted(tool)) return 'hosted';
if (tool.license && tool.license !== 'Proprietary') return 'oss';
return 'proprietary';
}