introduce concepts phase 1-2
This commit is contained in:
parent
0648647c8a
commit
202ee5f801
@ -21,8 +21,10 @@ export interface Props {
|
|||||||
|
|
||||||
const { tool } = Astro.props;
|
const { tool } = Astro.props;
|
||||||
|
|
||||||
// Check if this is a method vs software
|
|
||||||
|
// Check types
|
||||||
const isMethod = tool.type === 'method';
|
const isMethod = tool.type === 'method';
|
||||||
|
const isConcept = tool.type === 'concept';
|
||||||
|
|
||||||
// Check if tool has a valid project URL (means we're hosting it)
|
// Check if tool has a valid project URL (means we're hosting it)
|
||||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||||
@ -34,7 +36,8 @@ const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
|||||||
const hasKnowledgebase = tool.knowledgebase === true;
|
const hasKnowledgebase = tool.knowledgebase === true;
|
||||||
|
|
||||||
// Determine card styling based on type and hosting status
|
// Determine card styling based on type and hosting status
|
||||||
const cardClass = isMethod ? 'card card-method tool-card' :
|
const cardClass = isConcept ? 'card card-concept tool-card' :
|
||||||
|
isMethod ? 'card card-method tool-card' :
|
||||||
hasValidProjectUrl ? 'card card-hosted tool-card' :
|
hasValidProjectUrl ? 'card card-hosted tool-card' :
|
||||||
(tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
|
(tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
|
||||||
---
|
---
|
||||||
@ -99,9 +102,14 @@ const cardClass = isMethod ? 'card card-method tool-card' :
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Buttons - Fixed at Bottom -->
|
<!-- Buttons - Fixed at Bottom -->
|
||||||
<div class="tool-card-buttons" onclick="event.stopPropagation();">
|
<div class="tool-card-buttons" onclick="event.stopPropagation();">
|
||||||
{isMethod ? (
|
{isConcept ? (
|
||||||
|
<!-- Concept button -->
|
||||||
|
<a href={tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-concept); border-color: var(--color-concept);">
|
||||||
|
Mehr erfahren
|
||||||
|
</a>
|
||||||
|
) : isMethod ? (
|
||||||
<!-- Method button -->
|
<!-- Method button -->
|
||||||
<a href={tool.projectUrl || tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-method); border-color: var(--color-method);">
|
<a href={tool.projectUrl || tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-method); border-color: var(--color-method);">
|
||||||
Zur Methode
|
Zur Methode
|
||||||
|
@ -342,35 +342,6 @@ const sortedTags = Object.entries(tagFrequency)
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort filtered results: methods first, then self-hosted, then OSS, proprietary last
|
|
||||||
filtered.sort((a, b) => {
|
|
||||||
const aMethod = isMethod(a);
|
|
||||||
const bMethod = isMethod(b);
|
|
||||||
const aHosted = isToolHosted(a);
|
|
||||||
const bHosted = isToolHosted(b);
|
|
||||||
const aProprietary = !aMethod && a.license === 'Proprietary';
|
|
||||||
const bProprietary = !bMethod && b.license === 'Proprietary';
|
|
||||||
|
|
||||||
// Methods first
|
|
||||||
//if (aMethod && !bMethod) return -1;
|
|
||||||
//if (!aMethod && bMethod) return 1;
|
|
||||||
|
|
||||||
// If both are methods or both are tools
|
|
||||||
if (aMethod === bMethod) {
|
|
||||||
// Self-hosted tools first (regardless of license)
|
|
||||||
if (aHosted && !bHosted) return -1;
|
|
||||||
if (!aHosted && bHosted) return 1;
|
|
||||||
|
|
||||||
// If both have same hosting status, proprietary tools go last
|
|
||||||
if (aHosted === bHosted) {
|
|
||||||
if (!aProprietary && bProprietary) return -1;
|
|
||||||
if (aProprietary && !bProprietary) return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update matrix highlighting
|
// Update matrix highlighting
|
||||||
updateMatrixHighlighting();
|
updateMatrixHighlighting();
|
||||||
// Emit custom event with filtered results
|
// Emit custom event with filtered results
|
||||||
@ -417,17 +388,7 @@ const sortedTags = Object.entries(tagFrequency)
|
|||||||
window.dispatchEvent(new CustomEvent('viewChanged', { detail: view }));
|
window.dispatchEvent(new CustomEvent('viewChanged', { detail: view }));
|
||||||
|
|
||||||
if (view === 'hosted') {
|
if (view === 'hosted') {
|
||||||
const hosted = window.toolsData.filter(tool => isToolHosted(tool));
|
const hosted = window.toolsData.filter(tool => isToolHosted(tool));
|
||||||
hosted.sort((a, b) => {
|
|
||||||
const aProprietary = a.license === 'Proprietary';
|
|
||||||
const bProprietary = b.license === 'Proprietary';
|
|
||||||
|
|
||||||
if (!aProprietary && bProprietary) return -1;
|
|
||||||
if (aProprietary && !bProprietary) return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: hosted }));
|
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: hosted }));
|
||||||
} else {
|
} else {
|
||||||
filterTools();
|
filterTools();
|
||||||
|
@ -24,6 +24,7 @@ domains.forEach((domain: any) => {
|
|||||||
matrix[domain.id] = {};
|
matrix[domain.id] = {};
|
||||||
phases.forEach((phase: any) => {
|
phases.forEach((phase: any) => {
|
||||||
matrix[domain.id][phase.id] = tools.filter((tool: any) =>
|
matrix[domain.id][phase.id] = tools.filter((tool: any) =>
|
||||||
|
tool.type !== 'concept' && // Exclude concepts from matrix
|
||||||
tool.domains && tool.domains.includes(domain.id) &&
|
tool.domains && tool.domains.includes(domain.id) &&
|
||||||
tool.phases && tool.phases.includes(phase.id)
|
tool.phases && tool.phases.includes(phase.id)
|
||||||
);
|
);
|
||||||
@ -407,6 +408,11 @@ domains.forEach((domain: any) => {
|
|||||||
|
|
||||||
// Re-populate with filtered tools based on domains × phases
|
// Re-populate with filtered tools based on domains × phases
|
||||||
filtered.forEach(tool => {
|
filtered.forEach(tool => {
|
||||||
|
// Skip concepts - they don't belong in matrix
|
||||||
|
if (tool.type === 'concept') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isMethod = tool.type === 'method';
|
const isMethod = tool.type === 'method';
|
||||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||||
tool.projectUrl !== null &&
|
tool.projectUrl !== null &&
|
||||||
|
@ -1904,6 +1904,95 @@ tools:
|
|||||||
- jamf
|
- jamf
|
||||||
- enterprise
|
- enterprise
|
||||||
- commandline
|
- commandline
|
||||||
|
- name: Regular Expressions (Regex)
|
||||||
|
icon: 🔤
|
||||||
|
type: concept
|
||||||
|
description: >-
|
||||||
|
Pattern matching language for searching, extracting, and manipulating text.
|
||||||
|
Essential for log analysis, malware signature creation, and data extraction from
|
||||||
|
unstructured sources. Forms the backbone of many forensic tools and custom scripts.
|
||||||
|
domains:
|
||||||
|
- incident-response
|
||||||
|
- malware-analysis
|
||||||
|
- network-forensics
|
||||||
|
- fraud-investigation
|
||||||
|
phases:
|
||||||
|
- examination
|
||||||
|
- analysis
|
||||||
|
platforms: []
|
||||||
|
domain-agnostic-software: null
|
||||||
|
skillLevel: intermediate
|
||||||
|
accessType: null
|
||||||
|
url: https://regexr.com/
|
||||||
|
projectUrl: null
|
||||||
|
license: null
|
||||||
|
knowledgebase: false
|
||||||
|
tags:
|
||||||
|
- pattern-matching
|
||||||
|
- text-processing
|
||||||
|
- log-analysis
|
||||||
|
- string-manipulation
|
||||||
|
- search-algorithms
|
||||||
|
|
||||||
|
- name: SQL Query Fundamentals
|
||||||
|
icon: 🗃️
|
||||||
|
type: concept
|
||||||
|
description: >-
|
||||||
|
Structured Query Language for database interrogation and analysis. Critical for
|
||||||
|
examining application databases, SQLite artifacts from mobile devices, and
|
||||||
|
browser history databases. Enables complex correlation and filtering of large datasets.
|
||||||
|
domains:
|
||||||
|
- incident-response
|
||||||
|
- mobile-forensics
|
||||||
|
- fraud-investigation
|
||||||
|
- cloud-forensics
|
||||||
|
phases:
|
||||||
|
- examination
|
||||||
|
- analysis
|
||||||
|
platforms: []
|
||||||
|
domain-agnostic-software: null
|
||||||
|
skillLevel: intermediate
|
||||||
|
accessType: null
|
||||||
|
url: https://www.w3schools.com/sql/
|
||||||
|
projectUrl: null
|
||||||
|
license: null
|
||||||
|
knowledgebase: false
|
||||||
|
tags:
|
||||||
|
- database-analysis
|
||||||
|
- query-language
|
||||||
|
- data-correlation
|
||||||
|
- mobile-artifacts
|
||||||
|
- browser-forensics
|
||||||
|
|
||||||
|
- name: Hash Functions & Digital Signatures
|
||||||
|
icon: 🔐
|
||||||
|
type: concept
|
||||||
|
description: >-
|
||||||
|
Cryptographic principles for data integrity verification and authentication.
|
||||||
|
Fundamental for evidence preservation, malware identification, and establishing
|
||||||
|
chain of custody. Understanding of MD5, SHA, and digital signature validation.
|
||||||
|
domains:
|
||||||
|
- incident-response
|
||||||
|
- law-enforcement
|
||||||
|
- malware-analysis
|
||||||
|
- cloud-forensics
|
||||||
|
phases:
|
||||||
|
- data-collection
|
||||||
|
- examination
|
||||||
|
platforms: []
|
||||||
|
domain-agnostic-software: null
|
||||||
|
skillLevel: advanced
|
||||||
|
accessType: null
|
||||||
|
url: https://en.wikipedia.org/wiki/Cryptographic_hash_function
|
||||||
|
projectUrl: null
|
||||||
|
license: null
|
||||||
|
knowledgebase: false
|
||||||
|
tags:
|
||||||
|
- cryptography
|
||||||
|
- data-integrity
|
||||||
|
- evidence-preservation
|
||||||
|
- malware-identification
|
||||||
|
- chain-of-custody
|
||||||
domains:
|
domains:
|
||||||
- id: incident-response
|
- id: incident-response
|
||||||
name: Incident Response & Breach-Untersuchung
|
name: Incident Response & Breach-Untersuchung
|
||||||
|
@ -112,6 +112,29 @@ const tools = data.tools;
|
|||||||
// Initial tools HTML
|
// Initial tools HTML
|
||||||
const initialToolsHTML = toolsContainer.innerHTML;
|
const initialToolsHTML = toolsContainer.innerHTML;
|
||||||
|
|
||||||
|
// Simple sorting function - no external imports needed
|
||||||
|
function sortTools(tools, sortBy = 'default') {
|
||||||
|
const sorted = [...tools]; // Don't mutate original array
|
||||||
|
|
||||||
|
switch (sortBy) {
|
||||||
|
case 'alphabetical':
|
||||||
|
return sorted.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
case 'difficulty':
|
||||||
|
const difficultyOrder = { 'novice': 0, 'beginner': 1, 'intermediate': 2, 'advanced': 3, 'expert': 4 };
|
||||||
|
return sorted.sort((a, b) =>
|
||||||
|
(difficultyOrder[a.skillLevel] || 999) - (difficultyOrder[b.skillLevel] || 999)
|
||||||
|
);
|
||||||
|
case 'type':
|
||||||
|
const typeOrder = { 'concept': 0, 'method': 1, 'software': 2 };
|
||||||
|
return sorted.sort((a, b) =>
|
||||||
|
(typeOrder[a.type] || 999) - (typeOrder[b.type] || 999)
|
||||||
|
);
|
||||||
|
case 'default':
|
||||||
|
default:
|
||||||
|
return sorted; // No sorting - embrace the entropy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Authentication check function
|
// Authentication check function
|
||||||
async function checkAuthentication() {
|
async function checkAuthentication() {
|
||||||
try {
|
try {
|
||||||
@ -177,7 +200,7 @@ const tools = data.tools;
|
|||||||
|
|
||||||
// Hide filter controls in AI mode - AGGRESSIVE APPROACH
|
// Hide filter controls in AI mode - AGGRESSIVE APPROACH
|
||||||
const domainPhaseContainer = document.querySelector('.domain-phase-container') as HTMLElement;
|
const domainPhaseContainer = document.querySelector('.domain-phase-container') as HTMLElement;
|
||||||
const searchInput = document.getElementById('search-tools') as HTMLElement;
|
const searchInput = document.getElementById('search-input') as HTMLElement;
|
||||||
const tagCloud = document.querySelector('.tag-cloud') as HTMLElement;
|
const tagCloud = document.querySelector('.tag-cloud') as HTMLElement;
|
||||||
// Hide all checkbox wrappers
|
// Hide all checkbox wrappers
|
||||||
const checkboxWrappers = document.querySelectorAll('.checkbox-wrapper');
|
const checkboxWrappers = document.querySelectorAll('.checkbox-wrapper');
|
||||||
@ -227,7 +250,7 @@ const tools = data.tools;
|
|||||||
|
|
||||||
// Show filter controls in matrix mode
|
// Show filter controls in matrix mode
|
||||||
const domainPhaseContainerMatrix = document.querySelector('.domain-phase-container') as HTMLElement;
|
const domainPhaseContainerMatrix = document.querySelector('.domain-phase-container') as HTMLElement;
|
||||||
const searchInputMatrix = document.getElementById('search-tools') as HTMLElement;
|
const searchInputMatrix = document.getElementById('search-input') as HTMLElement;
|
||||||
const tagCloudMatrix = document.querySelector('.tag-cloud') as HTMLElement;
|
const tagCloudMatrix = document.querySelector('.tag-cloud') as HTMLElement;
|
||||||
const checkboxWrappersMatrix = document.querySelectorAll('.checkbox-wrapper');
|
const checkboxWrappersMatrix = document.querySelectorAll('.checkbox-wrapper');
|
||||||
const tagHeaderMatrix = document.querySelector('.tag-header') as HTMLElement;
|
const tagHeaderMatrix = document.querySelector('.tag-header') as HTMLElement;
|
||||||
@ -262,7 +285,7 @@ const tools = data.tools;
|
|||||||
|
|
||||||
// Show filter controls in grid mode
|
// Show filter controls in grid mode
|
||||||
const domainPhaseContainerGrid = document.querySelector('.domain-phase-container') as HTMLElement;
|
const domainPhaseContainerGrid = document.querySelector('.domain-phase-container') as HTMLElement;
|
||||||
const searchInputGrid = document.getElementById('search-tools') as HTMLElement;
|
const searchInputGrid = document.getElementById('search-input') as HTMLElement;
|
||||||
const tagCloudGrid = document.querySelector('.tag-cloud') as HTMLElement;
|
const tagCloudGrid = document.querySelector('.tag-cloud') as HTMLElement;
|
||||||
const checkboxWrappersGrid = document.querySelectorAll('.checkbox-wrapper');
|
const checkboxWrappersGrid = document.querySelectorAll('.checkbox-wrapper');
|
||||||
const tagHeaderGrid = document.querySelector('.tag-header') as HTMLElement;
|
const tagHeaderGrid = document.querySelector('.tag-header') as HTMLElement;
|
||||||
@ -318,8 +341,12 @@ const tools = data.tools;
|
|||||||
} else {
|
} else {
|
||||||
noResults.style.display = 'none';
|
noResults.style.display = 'none';
|
||||||
|
|
||||||
// Render filtered tools
|
// Apply sorting here - single place for all sorting logic
|
||||||
filtered.forEach((tool: any) => {
|
const currentSortOption = 'default'; // Will be dynamic later
|
||||||
|
const sortedTools = sortTools(filtered, currentSortOption);
|
||||||
|
|
||||||
|
// Render sorted tools
|
||||||
|
sortedTools.forEach((tool: any) => {
|
||||||
const toolCard = createToolCard(tool);
|
const toolCard = createToolCard(tool);
|
||||||
toolsContainer.appendChild(toolCard);
|
toolsContainer.appendChild(toolCard);
|
||||||
});
|
});
|
||||||
@ -338,6 +365,7 @@ const tools = data.tools;
|
|||||||
|
|
||||||
function createToolCard(tool) {
|
function createToolCard(tool) {
|
||||||
const isMethod = tool.type === 'method';
|
const isMethod = tool.type === 'method';
|
||||||
|
const isConcept = tool.type === 'concept';
|
||||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||||
tool.projectUrl !== null &&
|
tool.projectUrl !== null &&
|
||||||
tool.projectUrl !== "" &&
|
tool.projectUrl !== "" &&
|
||||||
@ -346,7 +374,8 @@ function createToolCard(tool) {
|
|||||||
const hasKnowledgebase = tool.knowledgebase === true;
|
const hasKnowledgebase = tool.knowledgebase === true;
|
||||||
|
|
||||||
const cardDiv = document.createElement('div');
|
const cardDiv = document.createElement('div');
|
||||||
const cardClass = isMethod ? 'card card-method tool-card' :
|
const cardClass = isConcept ? 'card card-concept tool-card' :
|
||||||
|
isMethod ? 'card card-method tool-card' :
|
||||||
hasValidProjectUrl ? 'card card-hosted tool-card' :
|
hasValidProjectUrl ? 'card card-hosted tool-card' :
|
||||||
(tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
|
(tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
|
||||||
cardDiv.className = cardClass;
|
cardDiv.className = cardClass;
|
||||||
@ -358,7 +387,7 @@ function createToolCard(tool) {
|
|||||||
<div class="tool-card-header">
|
<div class="tool-card-header">
|
||||||
<h3>${tool.icon ? `<span style="margin-right: 0.5rem; font-size: 1.125rem;">${tool.icon}</span>` : ''}${tool.name}</h3>
|
<h3>${tool.icon ? `<span style="margin-right: 0.5rem; font-size: 1.125rem;">${tool.icon}</span>` : ''}${tool.name}</h3>
|
||||||
<div class="tool-card-badges">
|
<div class="tool-card-badges">
|
||||||
${!isMethod && hasValidProjectUrl ? '<span class="badge badge-primary">CC24-Server</span>' : ''}
|
${!isMethod && !isConcept && hasValidProjectUrl ? '<span class="badge badge-primary">CC24-Server</span>' : ''}
|
||||||
${hasKnowledgebase ? '<span class="badge badge-error">📖</span>' : ''}
|
${hasKnowledgebase ? '<span class="badge badge-error">📖</span>' : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -395,7 +424,7 @@ function createToolCard(tool) {
|
|||||||
<polyline points="14 2 14 8 20 8"></polyline>
|
<polyline points="14 2 14 8 20 8"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
|
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
|
||||||
${isMethod ? 'Methode' : tool.license === 'Proprietary' ? 'Prop.' : tool.license?.split(' ')[0] || 'N/A'}
|
${isConcept ? 'Konzept' : isMethod ? 'Methode' : tool.license === 'Proprietary' ? 'Prop.' : tool.license?.split(' ')[0] || 'N/A'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -405,7 +434,11 @@ function createToolCard(tool) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tool-card-buttons" onclick="event.stopPropagation();">
|
<div class="tool-card-buttons" onclick="event.stopPropagation();">
|
||||||
${isMethod ? `
|
${isConcept ? `
|
||||||
|
<a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-concept); border-color: var(--color-concept);">
|
||||||
|
Mehr erfahren
|
||||||
|
</a>
|
||||||
|
` : isMethod ? `
|
||||||
<a href="${tool.projectUrl || tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-method); border-color: var(--color-method);">
|
<a href="${tool.projectUrl || tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button" style="background-color: var(--color-method); border-color: var(--color-method);">
|
||||||
Zur Methode
|
Zur Methode
|
||||||
</a>
|
</a>
|
||||||
|
@ -11,23 +11,28 @@
|
|||||||
:root {
|
:root {
|
||||||
/* Light Theme Colors */
|
/* Light Theme Colors */
|
||||||
--color-bg: #fff;
|
--color-bg: #fff;
|
||||||
--color-bg-secondary: #f5f5f5;
|
--color-bg-secondary: #f8fafc;
|
||||||
--color-bg-tertiary: #e0e0e0;
|
--color-bg-tertiary: #e2e8f0;
|
||||||
--color-text: #1a1a1a;
|
--color-text: #1e293b;
|
||||||
--color-text-secondary: #666;
|
--color-text-secondary: #64748b;
|
||||||
--color-border: #d0d0d0;
|
--color-border: #cbd5e1;
|
||||||
--color-primary: #2563eb;
|
--color-primary: #2563eb;
|
||||||
--color-primary-hover: #1d4ed8;
|
--color-primary-hover: #1d4ed8;
|
||||||
--color-accent: #10b981;
|
--color-accent: #059669;
|
||||||
--color-accent-hover: #059669;
|
--color-accent-hover: #047857;
|
||||||
--color-warning: #f59e0b;
|
--color-warning: #d97706;
|
||||||
--color-error: #ef4444;
|
--color-error: #dc2626;
|
||||||
--color-hosted: #8b5cf6;
|
|
||||||
|
/* Enhanced card type colors */
|
||||||
|
--color-hosted: #7c3aed; /* More vibrant purple */
|
||||||
--color-hosted-bg: #f3f0ff;
|
--color-hosted-bg: #f3f0ff;
|
||||||
--color-oss: #10b981;
|
--color-oss: #059669; /* Deeper green for better contrast */
|
||||||
--color-oss-bg: #ecfdf5;
|
--color-oss-bg: #ecfdf5;
|
||||||
--color-method: #3a90ed;
|
--color-method: #0891b2; /* Distinct teal-cyan for methods */
|
||||||
--color-method-bg: #f3f4f6;
|
--color-method-bg: #f0f9ff; /* Fixed: proper light background */
|
||||||
|
--color-concept: #ea580c; /* Warmer orange-red for concepts */
|
||||||
|
--color-concept-bg: #fff7ed;
|
||||||
|
|
||||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 5%);
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 5%);
|
||||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 10%);
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 10%);
|
||||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 10%);
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 10%);
|
||||||
@ -39,24 +44,29 @@
|
|||||||
|
|
||||||
[data-theme="dark"] {
|
[data-theme="dark"] {
|
||||||
/* Dark Theme Colors */
|
/* Dark Theme Colors */
|
||||||
--color-bg: #0f0f0f;
|
--color-bg: #0f172a;
|
||||||
--color-bg-secondary: #1a1a1a;
|
--color-bg-secondary: #1e293b;
|
||||||
--color-bg-tertiary: #262626;
|
--color-bg-tertiary: #334155;
|
||||||
--color-text: #e5e5e5;
|
--color-text: #f1f5f9;
|
||||||
--color-text-secondary: #a3a3a3;
|
--color-text-secondary: #94a3b8;
|
||||||
--color-border: #404040;
|
--color-border: #475569;
|
||||||
--color-primary: #3b82f6;
|
--color-primary: #3b82f6;
|
||||||
--color-primary-hover: #60a5fa;
|
--color-primary-hover: #60a5fa;
|
||||||
--color-accent: #34d399;
|
--color-accent: #10b981;
|
||||||
--color-accent-hover: #6ee7b7;
|
--color-accent-hover: #34d399;
|
||||||
--color-warning: #fbbf24;
|
--color-warning: #f59e0b;
|
||||||
--color-error: #f87171;
|
--color-error: #f87171;
|
||||||
--color-hosted: #a78bfa;
|
|
||||||
|
/* Enhanced dark card type colors */
|
||||||
|
--color-hosted: #a855f7; /* Brighter purple for dark mode */
|
||||||
--color-hosted-bg: #2e1065;
|
--color-hosted-bg: #2e1065;
|
||||||
--color-oss: #34d399;
|
--color-oss: #10b981; /* Vibrant green */
|
||||||
--color-oss-bg: #064e3b;
|
--color-oss-bg: #064e3b;
|
||||||
--color-method: #8bbdfa;
|
--color-method: #0891b2; /* Distinct teal-cyan */
|
||||||
--color-method-bg: #2e4e81;
|
--color-method-bg: #164e63; /* Proper dark background */
|
||||||
|
--color-concept: #f97316; /* Bright orange for dark mode */
|
||||||
|
--color-concept-bg: #7c2d12;
|
||||||
|
|
||||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 30%);
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 30%);
|
||||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 40%);
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 40%);
|
||||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 50%);
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 50%);
|
||||||
@ -313,6 +323,11 @@ input[type="checkbox"] {
|
|||||||
border-color: var(--color-method);
|
border-color: var(--color-method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-concept {
|
||||||
|
background-color: var(--color-concept-bg);
|
||||||
|
border-color: var(--color-concept);
|
||||||
|
}
|
||||||
|
|
||||||
.grid-auto-fit {
|
.grid-auto-fit {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 350px));
|
grid-template-columns: repeat(auto-fill, minmax(300px, 350px));
|
||||||
|
@ -6,7 +6,7 @@ import { z } from 'zod';
|
|||||||
const ToolSchema = z.object({
|
const ToolSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
icon: z.string().optional().nullable(),
|
icon: z.string().optional().nullable(),
|
||||||
type: z.string(),
|
type: z.enum(['software', 'method', 'concept']), // Make this more explicit
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
domains: z.array(z.string()).optional().nullable().default([]),
|
domains: z.array(z.string()).optional().nullable().default([]),
|
||||||
phases: z.array(z.string()).optional().nullable().default([]),
|
phases: z.array(z.string()).optional().nullable().default([]),
|
||||||
@ -127,15 +127,18 @@ export async function getToolsData(): Promise<ToolsData> {
|
|||||||
return cachedRandomizedData;
|
return cachedRandomizedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get compressed data for AI (removes projectUrl and statusUrl)
|
// Get compressed data for AI (removes projectUrl and statusUrl, excludes concepts)
|
||||||
export async function getCompressedToolsDataForAI(): Promise<CompressedToolsData> {
|
export async function getCompressedToolsDataForAI(): Promise<CompressedToolsData> {
|
||||||
if (!cachedCompressedData) {
|
if (!cachedCompressedData) {
|
||||||
const data = await getToolsData();
|
const data = await getToolsData();
|
||||||
|
|
||||||
const compressedTools = data.tools.map(tool => {
|
// Filter out concepts and compress remaining tools
|
||||||
const { projectUrl, statusUrl, ...compressedTool } = tool;
|
const compressedTools = data.tools
|
||||||
return compressedTool;
|
.filter(tool => tool.type !== 'concept') // Exclude concepts from AI
|
||||||
});
|
.map(tool => {
|
||||||
|
const { projectUrl, statusUrl, ...compressedTool } = tool;
|
||||||
|
return compressedTool;
|
||||||
|
});
|
||||||
|
|
||||||
cachedCompressedData = {
|
cachedCompressedData = {
|
||||||
tools: compressedTools,
|
tools: compressedTools,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user