refactor(snippets): adopt alias/title model and markdown UX
- rename snippet identity from name to alias and add required title fields - migrate snippet API, forms, cards, and detail views to alias/title semantics - render markdown descriptions with short card previews and split vendor chunks
This commit is contained in:
@@ -5,16 +5,29 @@ import { Settings, Pencil, Trash2, Plus, Download, Braces } from 'lucide-react';
|
||||
import { parse as yamlParse } from 'yaml';
|
||||
import { snippets } from '../../api';
|
||||
import type { Snippet } from '../../api';
|
||||
import { Breadcrumbs, Button, Card, ContextMenu, Timestamp, UuidBadge } from '../../ui';
|
||||
import { Breadcrumbs, Button, Card, ContextMenu, MarkdownContent, Timestamp, UuidBadge } from '../../ui';
|
||||
import styles from '../Page.module.css';
|
||||
|
||||
function firstParagraphBlocks(markdown: string, limit = 2): { preview: string; truncated: boolean } {
|
||||
const blocks = markdown
|
||||
.split(/\n\s*\n/g)
|
||||
.map((block) => block.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const sliced = blocks.slice(0, limit);
|
||||
return {
|
||||
preview: sliced.join('\n\n'),
|
||||
truncated: blocks.length > limit,
|
||||
};
|
||||
}
|
||||
|
||||
function SnippetCard({ snippet, onDelete }: { snippet: Snippet; onDelete: (id: string) => void }) {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const header = (
|
||||
<div className={styles.envCardHeader}>
|
||||
<span className={styles.envCardName}>{snippet.name}</span>
|
||||
<span className={styles.envCardName}>{snippet.title}</span>
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<ContextMenu
|
||||
align="right"
|
||||
@@ -56,7 +69,19 @@ function SnippetCard({ snippet, onDelete }: { snippet: Snippet; onDelete: (id: s
|
||||
footer={footer}
|
||||
onClick={() => navigate(`/snippets/${snippet.id}`)}
|
||||
>
|
||||
{snippet.description && <p className={styles.muted}>{snippet.description}</p>}
|
||||
<p className={styles.muted}>
|
||||
{t('snippets.field_alias')}: <code className={styles.codeInline}>{snippet.alias}</code>
|
||||
</p>
|
||||
{snippet.description && (() => {
|
||||
const { preview, truncated } = firstParagraphBlocks(snippet.description, 2);
|
||||
if (!preview) return null;
|
||||
return (
|
||||
<>
|
||||
<MarkdownContent content={preview} />
|
||||
{truncated && <p className={styles.muted}>...</p>}
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user