card.svelte 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. <script lang="ts">
  2. import type { ClassValue } from 'svelte/elements';
  3. import { resolve } from '$app/paths';
  4. import { GlassPane } from '$lib/components/common/glass-pane';
  5. import { Icon } from '$lib/components/common/icon';
  6. import { StatusBadge } from '$lib/components/common/status-badge';
  7. import { Tags } from '$lib/components/common/tags';
  8. import type { Tool } from '$lib/types/entities';
  9. let {
  10. tool,
  11. selectedTags,
  12. class: className = '',
  13. onselect,
  14. }: {
  15. tool: Tool;
  16. selectedTags?: Set<string>;
  17. class?: ClassValue;
  18. onselect?: () => void;
  19. } = $props();
  20. </script>
  21. {#snippet content()}
  22. <GlassPane class={['flex h-32 gap-4 overflow-hidden rounded-xl px-4 py-2', className]} reactive>
  23. <!-- icon -->
  24. <div class="flex shrink-0 items-center justify-center">
  25. <Icon icon={tool.icon} />
  26. </div>
  27. <div class="flex flex-1 flex-col gap-1 overflow-hidden">
  28. <!-- header: name + status badge -->
  29. <div class="flex items-center justify-between gap-2">
  30. <span class="truncate text-lg font-medium text-white/75 group-hover:text-white">
  31. {tool.name}
  32. </span>
  33. {#if tool.status}
  34. <StatusBadge class="shrink-0" status={tool.status} />
  35. {/if}
  36. </div>
  37. <!-- description -->
  38. {#if tool.description}
  39. <div class="line-clamp-2 text-sm text-white/50">
  40. {tool.description}
  41. </div>
  42. {:else}
  43. <div class="text-xs text-white/25">&lt;no description&gt;</div>
  44. {/if}
  45. <!-- tags -->
  46. <div class="mt-auto overflow-hidden">
  47. <Tags activeTags={selectedTags} tags={tool.tags} />
  48. </div>
  49. </div>
  50. </GlassPane>
  51. {/snippet}
  52. {#if onselect === undefined}
  53. <a class="group block" href={resolve('/workloads/tools/[id]', { id: tool.id })}>
  54. {@render content()}
  55. </a>
  56. {:else}
  57. <div
  58. class="group block"
  59. role="button"
  60. tabindex="0"
  61. onclick={() => onselect()}
  62. onkeydown={(e) => e.key === 'Enter' && onselect()}
  63. >
  64. {@render content()}
  65. </div>
  66. {/if}