anpassung matrix, impressum

This commit is contained in:
overcuriousity
2025-07-15 13:40:29 +02:00
parent 7667e7bd74
commit 6479de6e52
6 changed files with 259 additions and 55 deletions

View File

@@ -7,7 +7,7 @@
<div class="footer-content">
<div>
<p class="text-muted" style="margin: 0;">
© 2025 CC24-Hub - Academic Research Project
© 2025 CC24-Hub - Lizensiert unter BSD-3-Clause
</p>
</div>
<div style="display: flex; gap: 2rem; align-items: center;">

View File

@@ -73,7 +73,7 @@ const sortedTags = Object.entries(tagFrequency)
<!-- Additional Filters -->
<div style="margin-bottom: 1.5rem;">
<div class="checkbox-wrapper" style="margin-bottom: 1rem;">
<input type="checkbox" id="include-proprietary" !checked />
<input type="checkbox" id="include-proprietary" checked />
<label for="include-proprietary">Proprietäre Software mit einschließen</label>
</div>
@@ -137,7 +137,7 @@ const sortedTags = Object.entries(tagFrequency)
// Initialize tag cloud state
function initTagCloud() {
const visibleCount = 22; // Show first 12 tags initially
const visibleCount = 22;
tagCloudItems.forEach((item, index) => {
if (index >= visibleCount) {
item.style.display = 'none';
@@ -155,7 +155,6 @@ const sortedTags = Object.entries(tagFrequency)
tagCloudToggle.textContent = 'Weniger zeigen';
tagCloudToggle.setAttribute('data-expanded', 'true');
// Show all filtered tags
tagCloudItems.forEach(item => {
if (!item.classList.contains('hidden')) {
item.style.display = 'inline-flex';
@@ -166,7 +165,6 @@ const sortedTags = Object.entries(tagFrequency)
tagCloudToggle.textContent = 'Mehr zeigen';
tagCloudToggle.setAttribute('data-expanded', 'false');
// Show only first visible tags
let visibleIndex = 0;
tagCloudItems.forEach(item => {
if (!item.classList.contains('hidden')) {
@@ -180,7 +178,7 @@ const sortedTags = Object.entries(tagFrequency)
});
}
}
// Filter tag cloud based on search input
function filterTagCloud() {
const searchTerm = searchInput.value.toLowerCase();
@@ -205,7 +203,6 @@ const sortedTags = Object.entries(tagFrequency)
}
});
// Update toggle button visibility
const hasHiddenTags = Array.from(tagCloudItems).some(item =>
!item.classList.contains('hidden') && item.style.display === 'none'
);
@@ -219,6 +216,48 @@ const sortedTags = Object.entries(tagFrequency)
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
}
// Update matrix highlighting based on current filters
function updateMatrixHighlighting() {
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
if (currentView !== 'matrix') return;
const matrixTable = document.querySelector('.matrix-table');
if (!matrixTable) return;
// Clear existing highlights
matrixTable.querySelectorAll('.highlight-row, .highlight-column').forEach(el => {
el.classList.remove('highlight-row', 'highlight-column');
});
const selectedDomain = domainSelect.value;
// Highlight selected domain row
if (selectedDomain) {
const domainRow = matrixTable.querySelector(`tr[data-domain="${selectedDomain}"]`);
if (domainRow) {
domainRow.classList.add('highlight-row');
}
}
// Highlight selected phase column
if (selectedPhase) {
const phaseHeaders = matrixTable.querySelectorAll('thead th[data-phase]');
const phaseIndex = Array.from(phaseHeaders).findIndex(th =>
th.getAttribute('data-phase') === selectedPhase
);
if (phaseIndex >= 0) {
const columnIndex = phaseIndex + 1; // +1 because first column is domain names
matrixTable.querySelectorAll(`tr`).forEach(row => {
const cell = row.children[columnIndex];
if (cell) {
cell.classList.add('highlight-column');
}
});
}
}
}
// Filter function
function filterTools() {
@@ -276,10 +315,12 @@ const sortedTags = Object.entries(tagFrequency)
if (aProprietary && !bProprietary) return 1;
}
// Maintain existing order within same priority group
return 0;
});
// Update matrix highlighting
updateMatrixHighlighting();
// Emit custom event with filtered results
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: filtered }));
}
@@ -304,11 +345,9 @@ const sortedTags = Object.entries(tagFrequency)
const phase = button.getAttribute('data-phase');
if (selectedPhase === phase) {
// Deselect if already selected
selectedPhase = '';
button.classList.remove('active');
} else {
// Select new phase
phaseButtons.forEach(btn => btn.classList.remove('active'));
selectedPhase = phase;
button.classList.add('active');
@@ -325,17 +364,12 @@ const sortedTags = Object.entries(tagFrequency)
window.dispatchEvent(new CustomEvent('viewChanged', { detail: view }));
// Apply view-specific filters
if (view === 'hosted') {
// Filter for hosted tools only (tools with valid projectUrl)
const hosted = window.toolsData.filter(tool => isToolHosted(tool));
// Apply same sorting logic for consistency
hosted.sort((a, b) => {
const aProprietary = a.license === 'Proprietary';
const bProprietary = b.license === 'Proprietary';
// Since all are hosted, just sort by proprietary status
if (!aProprietary && bProprietary) return -1;
if (aProprietary && !bProprietary) return 1;

View File

@@ -39,8 +39,8 @@ domains.forEach((domain: any) => {
<h3 style="margin-bottom: 0.75rem; color: var(--color-text); font-size: 1.125rem;">Übergreifend & Kollaboration</h3>
<div class="collaboration-tools-compact" id="collaboration-tools-container">
{collaborationTools.map((tool: any) => {
const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
return (
@@ -75,13 +75,13 @@ domains.forEach((domain: any) => {
<tr>
<th style="width: 200px;">Domain / Phase</th>
{phases.filter((phase: any) => phase.id !== 'collaboration').map((phase: any) => (
<th>{phase.name}</th>
<th data-phase={phase.id}>{phase.name}</th>
))}
</tr>
</thead>
<tbody>
{domains.map((domain: any) => (
<tr>
<tr data-domain={domain.id}>
<th>{domain.name}</th>
{phases.filter((phase: any) => phase.id !== 'collaboration').map((phase: any) => (
<td class="matrix-cell" data-domain={domain.id} data-phase={phase.id}>
@@ -141,6 +141,85 @@ domains.forEach((domain: any) => {
return activePhaseButton ? activePhaseButton.getAttribute('data-phase') : '';
}
// Helper function to get selected domain from dropdown
function getSelectedDomain() {
const domainSelect = document.getElementById('domain-select');
return domainSelect ? domainSelect.value : '';
}
// Update matrix highlighting based on current filters
function updateMatrixHighlighting() {
const matrixTable = document.querySelector('.matrix-table');
if (!matrixTable) return;
// Clear existing highlights
matrixTable.querySelectorAll('.highlight-row, .highlight-column').forEach(el => {
el.classList.remove('highlight-row', 'highlight-column');
});
const selectedDomain = getSelectedDomain();
const selectedPhase = getSelectedPhase();
// Highlight selected domain row
if (selectedDomain) {
const domainRow = matrixTable.querySelector(`tr[data-domain="${selectedDomain}"]`);
if (domainRow) {
domainRow.classList.add('highlight-row');
}
}
// Highlight selected phase column
if (selectedPhase) {
const phaseHeaders = matrixTable.querySelectorAll('thead th[data-phase]');
const phaseIndex = Array.from(phaseHeaders).findIndex(th =>
th.getAttribute('data-phase') === selectedPhase
);
if (phaseIndex >= 0) {
const columnIndex = phaseIndex + 1; // +1 because first column is domain names
matrixTable.querySelectorAll(`tr`).forEach(row => {
const cell = row.children[columnIndex];
if (cell) {
cell.classList.add('highlight-column');
}
});
}
}
}
// Helper function to create compact collaboration tool cards for matrix view
function createCollaborationToolCardCompact(tool) {
const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
const cardDiv = document.createElement('div');
const cardClass = `collaboration-tool-compact ${hasValidProjectUrl ? 'hosted' : tool.license !== 'Proprietary' ? 'oss' : ''}`;
cardDiv.className = cardClass;
cardDiv.onclick = () => window.showToolDetails(tool.name);
cardDiv.innerHTML = `
<div class="tool-compact-header">
<h4 style="margin: 0; font-size: 0.875rem; font-weight: 600;">${tool.name}</h4>
<div style="display: flex; gap: 0.25rem;">
${hasValidProjectUrl ? '<span class="badge-mini badge-primary">Self-Hosted</span>' : ''}
${tool.license !== 'Proprietary' ? '<span class="badge-mini badge-success">OSS</span>' : ''}
</div>
</div>
<p style="font-size: 0.75rem; color: var(--color-text-secondary); margin: 0.25rem 0; line-height: 1.3;">
${tool.description}
</p>
<div style="display: flex; gap: 0.75rem; font-size: 0.6875rem; color: var(--color-text-secondary);">
<span>${tool.platforms.join(', ')}</span>
<span>•</span>
<span>${tool.skillLevel}</span>
</div>
`;
return cardDiv;
}
// Tool details functions
window.showToolDetails = function(toolName) {
const tool = toolsData.find(t => t.name === toolName);
@@ -219,7 +298,24 @@ domains.forEach((domain: any) => {
document.getElementById('modal-overlay').classList.remove('active');
document.getElementById('tool-details').classList.remove('active');
};
// Listen for view changes to trigger highlighting
window.addEventListener('viewChanged', (event) => {
const view = event.detail;
if (view === 'matrix') {
// Delay highlighting to ensure matrix is visible
setTimeout(updateMatrixHighlighting, 100);
}
});
// Listen for filter changes to update highlighting
window.addEventListener('toolsFiltered', (event) => {
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
if (currentView === 'matrix') {
setTimeout(updateMatrixHighlighting, 50);
}
});
// Update matrix on filter change
window.addEventListener('toolsFiltered', (event) => {
const filtered = event.detail;
@@ -296,40 +392,10 @@ domains.forEach((domain: any) => {
});
});
});
// Update highlighting after matrix content is updated
setTimeout(updateMatrixHighlighting, 50);
}
}
});
// Helper function to create compact collaboration tool cards for matrix view
function createCollaborationToolCardCompact(tool) {
const hasValidProjectUrl = tool.projectUrl !== undefined &&
tool.projectUrl !== null &&
tool.projectUrl !== "" &&
tool.projectUrl.trim() !== "";
const cardDiv = document.createElement('div');
const cardClass = `collaboration-tool-compact ${hasValidProjectUrl ? 'hosted' : tool.license !== 'Proprietary' ? 'oss' : ''}`;
cardDiv.className = cardClass;
cardDiv.onclick = () => window.showToolDetails(tool.name);
cardDiv.innerHTML = `
<div class="tool-compact-header">
<h4 style="margin: 0; font-size: 0.875rem; font-weight: 600;">${tool.name}</h4>
<div style="display: flex; gap: 0.25rem;">
${hasValidProjectUrl ? '<span class="badge-mini badge-primary">Self-Hosted</span>' : ''}
${tool.license !== 'Proprietary' ? '<span class="badge-mini badge-success">OSS</span>' : ''}
</div>
</div>
<p style="font-size: 0.75rem; color: var(--color-text-secondary); margin: 0.25rem 0; line-height: 1.3;">
${tool.description}
</p>
<div style="display: flex; gap: 0.75rem; font-size: 0.6875rem; color: var(--color-text-secondary);">
<span>${tool.platforms.join(', ')}</span>
<span>•</span>
<span>${tool.skillLevel}</span>
</div>
`;
return cardDiv;
}
</script>