managarten/packages/help/src/components/ChangelogEntry.svelte
Till JS 9bf73fffa3 fix(help): correct broken imports + tighten SupportedLanguage typing
Two unrelated bugs in the @mana/help package surface that together
accounted for ~40 type errors:

Broken component imports
  Ten components inside packages/help/src/components/ were importing
  from `'../types.js'` and `'./content'` — neither path resolves.
  The actual files are at `../ui-types` (where FAQSectionProps,
  FeaturesOverviewProps etc. live) and `../content` (where FAQItem,
  FeatureItem, FAQCategory live). Fix the imports to point at the
  real files. ESM resolution doesn't need `.js` suffixes when
  TypeScript is feeding tsc, and the existing index.ts already
  re-exports under the correct paths.

  Net: -19 type errors across:
    ChangelogEntry, ChangelogSection, ContactSection, FAQItem,
    FAQSection, FeatureCard, FeaturesOverview, GettingStartedGuide,
    HelpSearch, KeyboardShortcuts

content/help/index.ts SupportedLanguage cast
  `getManaHelpContent()` was passing `currentLocale` (typed `string`)
  into FAQ rows that expect a `SupportedLanguage` enum — 9 errors
  from each FAQ row. Add a small `asSupportedLanguage()` guard that
  validates the locale string against the union and falls back to
  'de' for unknown values. Single source of truth lives next to
  the function that needed it.

  Net: -9 type errors.

Combined with the spiral-db dist rebuild (local-only, gitignored)
and the previous Observable migration commit, the total error count
drops from 418 → 115.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:13:18 +02:00

152 lines
4.4 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="ts">
import type { ChangelogEntryProps } from '../ui-types';
let { item, translations }: ChangelogEntryProps = $props();
let expanded = $state(false);
function getTypeColor(type: string): string {
switch (type) {
case 'major':
return 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400';
case 'minor':
return 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400';
case 'patch':
return 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400';
case 'beta':
return 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400';
default:
return 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400';
}
}
function formatDate(date: Date): string {
return new Date(date).toLocaleDateString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
const typeLabels = translations.changelog.types;
const changeLabels = translations.changelog.labels;
</script>
<div class="border-b border-gray-200 py-4 dark:border-gray-700">
<button
type="button"
class="flex w-full items-start justify-between text-left"
onclick={() => (expanded = !expanded)}
>
<div>
<div class="flex flex-wrap items-center gap-2">
<span class="font-mono text-lg font-semibold text-gray-900 dark:text-gray-100">
v{item.version}
</span>
<span class={`rounded-full px-2 py-0.5 text-xs font-medium ${getTypeColor(item.type)}`}>
{typeLabels[item.type] ?? item.type}
</span>
{#if item.highlighted}
<span
class="rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400"
>
Featured
</span>
{/if}
</div>
<h4 class="mt-1 font-medium text-gray-800 dark:text-gray-200">
{item.title}
</h4>
<p class="text-sm text-gray-500 dark:text-gray-400">
{formatDate(item.releaseDate)}
</p>
</div>
<span
class="mt-1 text-gray-500 transition-transform duration-200 dark:text-gray-400"
class:rotate-180={expanded}
>
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</span>
</button>
{#if expanded}
<div class="mt-4 space-y-4">
{#if item.summary}
<p class="text-gray-600 dark:text-gray-400">{item.summary}</p>
{/if}
{#if item.changes}
{#if item.changes.features && item.changes.features.length > 0}
<div>
<h5 class="mb-2 text-sm font-semibold text-green-600 dark:text-green-400">
{changeLabels.features}
</h5>
<ul class="space-y-1">
{#each item.changes.features as change}
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<span class="text-green-500">+</span>
<span>
<strong>{change.title}</strong>
{#if change.description}
- {change.description}
{/if}
</span>
</li>
{/each}
</ul>
</div>
{/if}
{#if item.changes.improvements && item.changes.improvements.length > 0}
<div>
<h5 class="mb-2 text-sm font-semibold text-blue-600 dark:text-blue-400">
{changeLabels.improvements}
</h5>
<ul class="space-y-1">
{#each item.changes.improvements as change}
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<span class="text-blue-500"></span>
<span>
<strong>{change.title}</strong>
{#if change.description}
- {change.description}
{/if}
</span>
</li>
{/each}
</ul>
</div>
{/if}
{#if item.changes.bugfixes && item.changes.bugfixes.length > 0}
<div>
<h5 class="mb-2 text-sm font-semibold text-red-600 dark:text-red-400">
{changeLabels.bugFixes}
</h5>
<ul class="space-y-1">
{#each item.changes.bugfixes as change}
<li class="flex items-start gap-2 text-sm text-gray-600 dark:text-gray-400">
<span class="text-red-500">×</span>
<span>
<strong>{change.title}</strong>
{#if change.description}
- {change.description}
{/if}
</span>
</li>
{/each}
</ul>
</div>
{/if}
{/if}
{#if item.content}
<div class="prose prose-sm dark:prose-invert max-w-none">
{@html item.content}
</div>
{/if}
</div>
{/if}
</div>