styles updates
This commit is contained in:
		
							parent
							
								
									af23c04219
								
							
						
					
					
						commit
						8c1600fcc4
					
				
							
								
								
									
										17
									
								
								.env.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.env.example
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# AI Configuration
 | 
				
			||||||
 | 
					AI_API_ENDPOINT=https://aiendpoint.org
 | 
				
			||||||
 | 
					AI_API_KEY=your_apikey_here
 | 
				
			||||||
 | 
					AI_MODEL='ai_model_name_here'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# OIDC Configuration
 | 
				
			||||||
 | 
					OIDC_ENDPOINT=https://oidc-provider.org
 | 
				
			||||||
 | 
					OIDC_CLIENT_ID=your_oidc_client_id
 | 
				
			||||||
 | 
					OIDC_CLIENT_SECRET=your_oidc_client_secret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTHENTICATION_NECESSARY=false # Always set this to true in prod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application
 | 
				
			||||||
 | 
					PUBLIC_BASE_URL=http://localhost:4321
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NODE_ENV=development
 | 
				
			||||||
@ -33,73 +33,79 @@ const cardClass = hasValidProjectUrl ? 'card card-hosted tool-card' : (tool.lice
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class={cardClass} onclick={`window.showToolDetails('${tool.name}')`} style="cursor: pointer;">
 | 
					<div class={cardClass} onclick={`window.showToolDetails('${tool.name}')`} style="cursor: pointer;">
 | 
				
			||||||
  <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.75rem;">
 | 
					  <!-- Card Header with Fixed Height -->
 | 
				
			||||||
    <h3 style="margin: 0;">{tool.name}</h3>
 | 
					  <div class="tool-card-header">
 | 
				
			||||||
    <div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
 | 
					    <h3>{tool.name}</h3>
 | 
				
			||||||
 | 
					    <div class="tool-card-badges">
 | 
				
			||||||
      {hasValidProjectUrl && <span class="badge badge-primary">Self-Hosted</span>}
 | 
					      {hasValidProjectUrl && <span class="badge badge-primary">Self-Hosted</span>}
 | 
				
			||||||
      {tool.license !== 'Proprietary' && <span class="badge badge-success">Open Source</span>}
 | 
					      {tool.license !== 'Proprietary' && <span class="badge badge-success">OSS</span>}
 | 
				
			||||||
      {hasKnowledgebase && <span class="badge badge-error">Infos 📖</span>}
 | 
					      {hasKnowledgebase && <span class="badge badge-error">📖</span>}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <p class="text-muted" style="font-size: 0.875rem; margin-bottom: 1rem;">
 | 
					  <!-- Description - Truncated to 2 lines -->
 | 
				
			||||||
 | 
					  <p class="text-muted">
 | 
				
			||||||
    {tool.description}
 | 
					    {tool.description}
 | 
				
			||||||
  </p>
 | 
					  </p>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem;">
 | 
					  <!-- Metadata - Compact Icons with Better Alignment -->
 | 
				
			||||||
    <div style="display: flex; align-items: center; gap: 0.25rem;">
 | 
					  <div class="tool-card-metadata" style="display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-bottom: 0.75rem; line-height: 1;">
 | 
				
			||||||
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
					    <div class="metadata-item" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary); flex-shrink: 1; min-width: 0;">
 | 
				
			||||||
 | 
					      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink: 0;">
 | 
				
			||||||
        <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
 | 
					        <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
 | 
				
			||||||
        <line x1="9" y1="9" x2="15" y2="9"></line>
 | 
					        <line x1="9" y1="9" x2="15" y2="9"></line>
 | 
				
			||||||
        <line x1="9" y1="15" x2="15" y2="15"></line>
 | 
					        <line x1="9" y1="15" x2="15" y2="15"></line>
 | 
				
			||||||
      </svg>
 | 
					      </svg>
 | 
				
			||||||
      <span class="text-muted" style="font-size: 0.75rem;">
 | 
					      <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
 | 
				
			||||||
        {tool.platforms.join(', ')}
 | 
					        {tool.platforms.slice(0, 2).join(', ')}{tool.platforms.length > 2 ? '...' : ''}
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <div style="display: flex; align-items: center; gap: 0.25rem;">
 | 
					    <div class="metadata-item" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary); flex-shrink: 1; min-width: 0;">
 | 
				
			||||||
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
					      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink: 0;">
 | 
				
			||||||
        <circle cx="12" cy="12" r="10"></circle>
 | 
					        <circle cx="12" cy="12" r="10"></circle>
 | 
				
			||||||
        <path d="M12 6v6l4 2"></path>
 | 
					        <path d="M12 6v6l4 2"></path>
 | 
				
			||||||
      </svg>
 | 
					      </svg>
 | 
				
			||||||
      <span class="text-muted" style="font-size: 0.75rem;">
 | 
					      <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
 | 
				
			||||||
        {tool.skillLevel}
 | 
					        {tool.skillLevel}
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <div style="display: flex; align-items: center; gap: 0.25rem;">
 | 
					    <div class="metadata-item" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary); flex-shrink: 1; min-width: 0;">
 | 
				
			||||||
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
					      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink: 0;">
 | 
				
			||||||
        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
 | 
					        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
 | 
				
			||||||
        <polyline points="14 2 14 8 20 8"></polyline>
 | 
					        <polyline points="14 2 14 8 20 8"></polyline>
 | 
				
			||||||
      </svg>
 | 
					      </svg>
 | 
				
			||||||
      <span class="text-muted" style="font-size: 0.75rem;">
 | 
					      <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
 | 
				
			||||||
        {tool.license}
 | 
					        {tool.license === 'Proprietary' ? 'Prop.' : tool.license.split(' ')[0]}
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <div class="tool-tags-container" style="display: flex; flex-wrap: wrap; gap: 0.25rem; margin-bottom: 1rem;">
 | 
					  <!-- Tags - Two Lines with Fade -->
 | 
				
			||||||
    {tool.tags.map(tag => (
 | 
					  <div class="tool-tags-container">
 | 
				
			||||||
 | 
					    {tool.tags.slice(0, 8).map(tag => (
 | 
				
			||||||
      <span class="tag">{tag}</span>
 | 
					      <span class="tag">{tag}</span>
 | 
				
			||||||
    ))}
 | 
					    ))}
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <!-- Button section - dual buttons for hosted tools, single for others -->
 | 
					  <!-- Buttons - Fixed at Bottom -->
 | 
				
			||||||
  {hasValidProjectUrl ? (
 | 
					  <div class="tool-card-buttons" onclick="event.stopPropagation();">
 | 
				
			||||||
    <!-- Two buttons for tools we're hosting -->
 | 
					    {hasValidProjectUrl ? (
 | 
				
			||||||
    <div style="display: flex; gap: 0.5rem;" onclick="event.stopPropagation();">
 | 
					      <!-- Two buttons for hosted tools -->
 | 
				
			||||||
      <a href={tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-secondary" style="flex: 1;">
 | 
					      <div class="button-row">
 | 
				
			||||||
 | 
					        <a href={tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-secondary">
 | 
				
			||||||
 | 
					          Homepage
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					        <a href={tool.projectUrl} target="_blank" rel="noopener noreferrer" class="btn btn-primary">
 | 
				
			||||||
 | 
					          Zugreifen
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    ) : (
 | 
				
			||||||
 | 
					      <!-- Single button for external tools -->
 | 
				
			||||||
 | 
					      <a href={tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button">
 | 
				
			||||||
        Software-Homepage
 | 
					        Software-Homepage
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
      <a href={tool.projectUrl} target="_blank" rel="noopener noreferrer" class="btn btn-primary" style="flex: 1;">
 | 
					    )}
 | 
				
			||||||
        Zugreifen
 | 
					  </div>
 | 
				
			||||||
      </a>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  ) : (
 | 
					 | 
				
			||||||
    <!-- Single button for tools we're not hosting -->
 | 
					 | 
				
			||||||
    <a href={tool.url} target="_blank" rel="noopener noreferrer" class="btn btn-primary" style="width: 100%;" onclick="event.stopPropagation();">
 | 
					 | 
				
			||||||
      Software-Homepage
 | 
					 | 
				
			||||||
    </a>
 | 
					 | 
				
			||||||
  )}
 | 
					 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@ -347,86 +347,78 @@ 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 = hasValidProjectUrl ? 'card card-hosted' : (tool.license !== 'Proprietary' ? 'card card-oss' : 'card');
 | 
					  const cardClass = hasValidProjectUrl ? 'card card-hosted tool-card' : (tool.license !== 'Proprietary' ? 'card card-oss tool-card' : 'card tool-card');
 | 
				
			||||||
  cardDiv.className = cardClass;
 | 
					  cardDiv.className = cardClass;
 | 
				
			||||||
  cardDiv.style.cursor = 'pointer';
 | 
					  cardDiv.style.cursor = 'pointer';
 | 
				
			||||||
  cardDiv.onclick = () => (window as any).showToolDetails(tool.name);
 | 
					  cardDiv.onclick = () => (window as any).showToolDetails(tool.name);
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  // Create responsive button HTML
 | 
					 | 
				
			||||||
  let buttonHTML;
 | 
					 | 
				
			||||||
  if (hasValidProjectUrl) {
 | 
					 | 
				
			||||||
    // Two buttons for tools we're hosting - responsive layout
 | 
					 | 
				
			||||||
    buttonHTML = `
 | 
					 | 
				
			||||||
      <div class="button-container" style="display: flex; gap: 0.5rem;" onclick="event.stopPropagation();">
 | 
					 | 
				
			||||||
        <a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-secondary" style="flex: 1; text-align: center;">
 | 
					 | 
				
			||||||
          Software-Homepage
 | 
					 | 
				
			||||||
        </a>
 | 
					 | 
				
			||||||
        <a href="${tool.projectUrl}" target="_blank" rel="noopener noreferrer" class="btn btn-primary" style="flex: 1; text-align: center;">
 | 
					 | 
				
			||||||
          Zugreifen
 | 
					 | 
				
			||||||
        </a>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    `;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // Single button for tools we're not hosting
 | 
					 | 
				
			||||||
    buttonHTML = `
 | 
					 | 
				
			||||||
      <a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary" style="width: 100%; text-align: center;" onclick="event.stopPropagation();">
 | 
					 | 
				
			||||||
        Software-Homepage
 | 
					 | 
				
			||||||
      </a>
 | 
					 | 
				
			||||||
    `;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  cardDiv.innerHTML = `
 | 
					  cardDiv.innerHTML = `
 | 
				
			||||||
    <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.75rem; flex-wrap: wrap; gap: 0.5rem;">
 | 
					    <div class="tool-card-header">
 | 
				
			||||||
      <h3 style="margin: 0; flex: 1; min-width: 0;">${tool.name}</h3>
 | 
					      <h3>${tool.name}</h3>
 | 
				
			||||||
      <div style="display: flex; gap: 0.5rem; flex-wrap: wrap; flex-shrink: 0;">
 | 
					      <div class="tool-card-badges">
 | 
				
			||||||
        ${hasValidProjectUrl ? '<span class="badge badge-primary">Self-Hosted</span>' : ''}
 | 
					        ${hasValidProjectUrl ? '<span class="badge badge-primary">Self-Hosted</span>' : ''}
 | 
				
			||||||
        ${tool.license !== 'Proprietary' ? '<span class="badge badge-success">Open Source</span>' : ''}
 | 
					        ${tool.license !== 'Proprietary' ? '<span class="badge badge-success">OSS</span>' : ''}
 | 
				
			||||||
        ${hasKnowledgebase ? '<span class="badge badge-error">Infos 📖</span>' : ''}
 | 
					        ${hasKnowledgebase ? '<span class="badge badge-error">📖</span>' : ''}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <p class="text-muted" style="font-size: 0.875rem; margin-bottom: 1rem; line-height: 1.5;">
 | 
					    <p class="text-muted">
 | 
				
			||||||
      ${tool.description}
 | 
					      ${tool.description}
 | 
				
			||||||
    </p>
 | 
					    </p>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem;">
 | 
					    <div class="tool-card-metadata" style="display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-bottom: 0.75rem; line-height: 1;">
 | 
				
			||||||
      <div style="display: flex; align-items: center; gap: 0.25rem; flex-wrap: wrap;">
 | 
					      <div class="metadata-item" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary); flex-shrink: 1; min-width: 0;">
 | 
				
			||||||
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
					        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink: 0;">
 | 
				
			||||||
          <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
 | 
					          <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
 | 
				
			||||||
          <line x1="9" y1="9" x2="15" y2="9"></line>
 | 
					          <line x1="9" y1="9" x2="15" y2="9"></line>
 | 
				
			||||||
          <line x1="9" y1="15" x2="15" y2="15"></line>
 | 
					          <line x1="9" y1="15" x2="15" y2="15"></line>
 | 
				
			||||||
        </svg>
 | 
					        </svg>
 | 
				
			||||||
        <span class="text-muted" style="font-size: 0.75rem;">
 | 
					        <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
 | 
				
			||||||
          ${(tool.platforms || []).join(', ')}
 | 
					          ${(tool.platforms || []).slice(0, 2).join(', ')}${tool.platforms && tool.platforms.length > 2 ? '...' : ''}
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      <div style="display: flex; align-items: center; gap: 0.25rem; flex-wrap: wrap;">
 | 
					      <div class="metadata-item" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary); flex-shrink: 1; min-width: 0;">
 | 
				
			||||||
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
					        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink: 0;">
 | 
				
			||||||
          <circle cx="12" cy="12" r="10"></circle>
 | 
					          <circle cx="12" cy="12" r="10"></circle>
 | 
				
			||||||
          <path d="M12 6v6l4 2"></path>
 | 
					          <path d="M12 6v6l4 2"></path>
 | 
				
			||||||
        </svg>
 | 
					        </svg>
 | 
				
			||||||
        <span class="text-muted" style="font-size: 0.75rem;">
 | 
					        <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
 | 
				
			||||||
          ${tool.skillLevel}
 | 
					          ${tool.skillLevel}
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      <div style="display: flex; align-items: center; gap: 0.25rem; flex-wrap: wrap;">
 | 
					      <div class="metadata-item" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary); flex-shrink: 1; min-width: 0;">
 | 
				
			||||||
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
					        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink: 0;">
 | 
				
			||||||
          <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
 | 
					          <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
 | 
				
			||||||
          <polyline points="14 2 14 8 20 8"></polyline>
 | 
					          <polyline points="14 2 14 8 20 8"></polyline>
 | 
				
			||||||
        </svg>
 | 
					        </svg>
 | 
				
			||||||
        <span class="text-muted" style="font-size: 0.75rem;">
 | 
					        <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;">
 | 
				
			||||||
          ${tool.license}
 | 
					          ${tool.license === 'Proprietary' ? 'Prop.' : tool.license.split(' ')[0]}
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <div style="display: flex; flex-wrap: wrap; gap: 0.25rem; margin-bottom: 1rem;">
 | 
					    <div class="tool-tags-container">
 | 
				
			||||||
      ${(tool.tags || []).map(tag => `<span class="tag">${tag}</span>`).join('')}
 | 
					      ${(tool.tags || []).slice(0, 8).map(tag => `<span class="tag">${tag}</span>`).join('')}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    ${buttonHTML}
 | 
					    <div class="tool-card-buttons" onclick="event.stopPropagation();">
 | 
				
			||||||
 | 
					      ${hasValidProjectUrl ? `
 | 
				
			||||||
 | 
					        <div class="button-row">
 | 
				
			||||||
 | 
					          <a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-secondary">
 | 
				
			||||||
 | 
					            Homepage
 | 
				
			||||||
 | 
					          </a>
 | 
				
			||||||
 | 
					          <a href="${tool.projectUrl}" target="_blank" rel="noopener noreferrer" class="btn btn-primary">
 | 
				
			||||||
 | 
					            Zugreifen
 | 
				
			||||||
 | 
					          </a>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ` : `
 | 
				
			||||||
 | 
					        <a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary single-button">
 | 
				
			||||||
 | 
					          Software-Homepage
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      `}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
  `;
 | 
					  `;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  return cardDiv;
 | 
					  return cardDiv;
 | 
				
			||||||
 | 
				
			|||||||
@ -309,9 +309,8 @@ input[type="checkbox"] {
 | 
				
			|||||||
  box-shadow: 0 0 0 1px var(--color-hosted);
 | 
					  box-shadow: 0 0 0 1px var(--color-hosted);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Adjust gradient for different card types */
 | 
					 | 
				
			||||||
.card-hosted .tool-tags-container::after {
 | 
					.card-hosted .tool-tags-container::after {
 | 
				
			||||||
  background: linear-gradient(to bottom, transparent 0%, var(--color-hosted-bg) 80%);
 | 
					  background: linear-gradient(to right, transparent 0%, var(--color-hosted-bg) 70%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.card-oss {
 | 
					.card-oss {
 | 
				
			||||||
@ -320,7 +319,7 @@ input[type="checkbox"] {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.card-oss .tool-tags-container::after {
 | 
					.card-oss .tool-tags-container::after {
 | 
				
			||||||
  background: linear-gradient(to bottom, transparent 0%, var(--color-oss-bg) 80%);
 | 
					  background: linear-gradient(to right, transparent 0%, var(--color-oss-bg) 70%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Grid and Layout */
 | 
					/* Grid and Layout */
 | 
				
			||||||
@ -456,36 +455,110 @@ input[type="checkbox"] {
 | 
				
			|||||||
  box-shadow: inset 0 0 0 1px rgb(59 130 246 / 40%);
 | 
					  box-shadow: inset 0 0 0 1px rgb(59 130 246 / 40%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Tool Card Description Truncation - 4 lines max */
 | 
					.tool-card {
 | 
				
			||||||
 | 
					  height: 300px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  padding: 1.25rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Card Header - Fixed Height */
 | 
				
			||||||
 | 
					.tool-card .tool-card-header {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  align-items: flex-start;
 | 
				
			||||||
 | 
					  min-height: 2.5rem;
 | 
				
			||||||
 | 
					  margin-bottom: 0.75rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tool-card .tool-card-header h3 {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  font-size: 1.125rem;
 | 
				
			||||||
 | 
					  line-height: 1.3;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  margin-right: 0.75rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tool-card .tool-card-badges {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 0.375rem;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					  flex-shrink: 0;
 | 
				
			||||||
 | 
					  align-items: flex-start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tool-card .text-muted {
 | 
					.tool-card .text-muted {
 | 
				
			||||||
  display: -webkit-box !important;
 | 
					  display: -webkit-box;
 | 
				
			||||||
  -webkit-line-clamp: 4;
 | 
					  -webkit-line-clamp: 3;
 | 
				
			||||||
  line-clamp: 4;
 | 
					  line-clamp: 3;
 | 
				
			||||||
  -webkit-box-orient: vertical;
 | 
					  -webkit-box-orient: vertical;
 | 
				
			||||||
  overflow: hidden !important;
 | 
					  overflow: hidden;
 | 
				
			||||||
  line-height: 1.4;
 | 
					  line-height: 1.4;
 | 
				
			||||||
  max-height: calc(1.4em * 4);
 | 
					  max-height: calc(1.4em * 3);
 | 
				
			||||||
 | 
					  font-size: 0.875rem;
 | 
				
			||||||
 | 
					  margin-bottom: 1rem;
 | 
				
			||||||
 | 
					  word-break: break-word;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Tool Card Tags Truncation - 3 lines max (uses height approach since we need flex) */
 | 
					/* Tool Card Tags - 2 lines max with better spacing */
 | 
				
			||||||
.tool-card .tool-tags-container {
 | 
					.tool-card .tool-tags-container {
 | 
				
			||||||
  max-height: calc(1.5em * 3 + 0.5rem) !important; /* 3 lines + gap space */
 | 
					  display: flex;
 | 
				
			||||||
  overflow: hidden !important;
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					  gap: 0.25rem;
 | 
				
			||||||
 | 
					  max-height: 2.5rem;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  margin-bottom: 1rem;
 | 
				
			||||||
 | 
					  flex-shrink: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Add subtle fade for truncated tags */
 | 
					.tool-card .tag {
 | 
				
			||||||
 | 
					  font-size: 0.75rem;
 | 
				
			||||||
 | 
					  padding: 0.25rem 0.5rem;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Subtle fade effect for truncated tags */
 | 
				
			||||||
.tool-card .tool-tags-container::after {
 | 
					.tool-card .tool-tags-container::after {
 | 
				
			||||||
  content: '';
 | 
					  content: '';
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  bottom: 0;
 | 
					  bottom: 0;
 | 
				
			||||||
  left: 0;
 | 
					 | 
				
			||||||
  right: 0;
 | 
					  right: 0;
 | 
				
			||||||
  height: 1.2em;
 | 
					  width: 3rem;
 | 
				
			||||||
  background: linear-gradient(to bottom, transparent 0%, var(--color-bg) 80%);
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  background: linear-gradient(to right, transparent 0%, var(--color-bg) 70%);
 | 
				
			||||||
  pointer-events: none;
 | 
					  pointer-events: none;
 | 
				
			||||||
 | 
					  opacity: 0.8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tool-card .tool-card-buttons {
 | 
				
			||||||
 | 
					  margin-top: auto;
 | 
				
			||||||
 | 
					  flex-shrink: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tool-card .button-row {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 0.5rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tool-card .button-row .btn {
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  font-size: 0.8125rem;
 | 
				
			||||||
 | 
					  padding: 0.625rem 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tool-card .single-button {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  font-size: 0.8125rem;
 | 
				
			||||||
 | 
					  padding: 0.625rem 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Normal sized badges */
 | 
				
			||||||
 | 
					.tool-card .badge {
 | 
				
			||||||
 | 
					  font-size: 0.75rem;
 | 
				
			||||||
 | 
					  padding: 0.25rem 0.5rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.tool-chip {
 | 
					.tool-chip {
 | 
				
			||||||
  display: inline-block;
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user