Tạo Custom MDX Components với Svelte trong Starlight
Tạo Custom MDX Components với Svelte trong Starlight
Section titled “Tạo Custom MDX Components với Svelte trong Starlight”Vấn đề
Section titled “Vấn đề”Bạn đã thêm Svelte vào Starlight nhưng không biết cách tạo custom components như:
:::code- Code blocks với filename, syntax highlighting:::terminal- Terminal output với copy button:::alert- Thông báo alerts với nhiều types:::checklist- Checklist có thể tích:::tabs- Code tabs cho nhiều languages
Giải pháp
Section titled “Giải pháp”Bước 1: Cài đặt Svelte trong Starlight
Section titled “Bước 1: Cài đặt Svelte trong Starlight”Đã có sẵn trong project! Kiểm tra:
import svelte from '@astrojs/svelte';
export default defineConfig({ integrations: [svelte()],});Bước 2: Tạo Custom Components
Section titled “Bước 2: Tạo Custom Components”Tạo các Svelte components trong src/components/:
---interface Props { type?: 'info' | 'warning' | 'success' | 'error'; title?: string;}
const { type = 'info', title } = Astro.props;
const icons = { info: 'ℹ️', warning: '⚠️', success: '✅', error: '❌'};
const colors = { info: '#3b82f6', warning: '#f59e0b', success: '#10b981', error: '#ef4444'};---
<div class="alert" data-type={type}> <div class="alert-header"> <span class="icon">{icons[type]}</span> {title && <span class="title">{title}</span>} </div> <div class="alert-content"> <slot /> </div></div>
<style define:vars={{ color: colors[type] }}> .alert { border-left: 4px solid var(--color); background: rgba(var(--color-rgb), 0.1); border-radius: 8px; padding: 1rem; margin: 1rem 0; }
.alert-header { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; margin-bottom: 0.5rem; }</style><script> export let title = 'Terminal';
let copied = false;
function copyCode() { const code = document.querySelector('.terminal-content code')?.textContent || ''; navigator.clipboard.writeText(code); copied = true; setTimeout(() => copied = false, 2000); }</script>
<div class="terminal"> <div class="terminal-header"> <span class="terminal-title">{title}</span> <button class="copy-btn" on:click={copyCode}> {copied ? '✅ Copied!' : '📋 Copy'} </button> </div> <div class="terminal-content"> <slot /> </div></div>
<style> .terminal { background: #1e1e1e; border-radius: 8px; overflow: hidden; margin: 1rem 0; }
.terminal-header { background: #2d2d2d; padding: 0.5rem 1rem; display: flex; justify-content: space-between; align-items: center; }
.terminal-content { padding: 1rem; color: #d4d4d4; font-family: 'Fira Code', monospace; overflow-x: auto; }
.copy-btn { background: transparent; border: 1px solid #555; color: #aaa; padding: 0.25rem 0.5rem; border-radius: 4px; cursor: pointer; font-size: 0.75rem; }
.copy-btn:hover { background: #444; color: white; }</style><script> export let language = 'javascript'; export let filename = ''; export let highlightLines = ''; export let lineNumbers = false; export let copyButton = true;
let copied = false;
function copyCode() { const code = document.querySelector('.code-content')?.textContent || ''; navigator.clipboard.writeText(code); copied = true; setTimeout(() => copied = false, 2000); }</script>
<div class="code-block"> {#if filename || copyButton} <div class="code-header"> {#if filename} <span class="filename">{filename}</span> {/if} {#if copyButton} <button class="copy-btn" on:click={copyCode}> {copied ? '✓' : '⧉'} </button> {/if} </div> {/if} <pre class="code-content" class:line-numbers={lineNumbers}><code class="language-{language}"><slot /></code></pre></div>
<style> .code-block { background: #1e1e1e; border-radius: 8px; overflow: hidden; margin: 1rem 0; }
.code-header { background: #2d2d2d; padding: 0.5rem 1rem; display: flex; justify-content: space-between; align-items: center; }
.filename { color: #888; font-size: 0.875rem; }
.copy-btn { background: transparent; border: none; color: #888; cursor: pointer; font-size: 1rem; }
.code-content { padding: 1rem; margin: 0; overflow-x: auto; color: #d4d4d4; }</style>Bước 3: Đăng ký Components trong Starlight
Section titled “Bước 3: Đăng ký Components trong Starlight”Cập nhật astro.config.mjs:
import starlight from '@astrojs/starlight';import { defineConfig } from 'astro/config';
export default defineConfig({ integrations: [ starlight({ title: 'My Docs', components: { // Custom Alert 'Aside': './src/components/Alert.astro', }, }), ],});Bước 4: Sử dụng trong MDX
Section titled “Bước 4: Sử dụng trong MDX”import Alert from '../../components/Alert.astro';import Terminal from '../../components/Terminal.svelte';import CodeBlock from '../../components/CodeBlock.svelte';
# Bài viết
<Alert type="info" title="Lưu ý"> Đây là thông tin quan trọng!</Alert>
<Terminal title="Cài đặt">$ npm install astro✓ Installed 1 package</Terminal>
<CodeBlock language="javascript" filename="config.js">export default defineConfig({ site: 'https://example.com'});</CodeBlock>Starlight Built-in Components (Miễn phí!)
Section titled “Starlight Built-in Components (Miễn phí!)”Starlight có sẵn nhiều components:
| Component | Cách dùng | Mô tả |
|---|---|---|
| Aside | <aside type="note"> | Thay thế alert |
| Steps | <Steps>{...}</Steps> | Numbered steps |
| Tabs | <TabItem> | Code/language tabs |
| FileTree | <FileTree> | File directory structure |
Ví dụ Aside (thay alert):
Section titled “Ví dụ Aside (thay alert):”import { Aside } from '@astrojs/starlight/components';
<Aside type="note"> Đây là thông tin!</Aside>
<Aside type="tip"> Mẹo hữu ích</Aside>
<Aside type="caution"> Cần cẩn thận</Aside>
<Aside type="danger"> Nguy hiểm!</Aside>Ví dụ Steps:
Section titled “Ví dụ Steps:”import { Steps } from '@astrojs/starlight/components';
<Steps>1. Cài đặt Astro2. Tạo project3. Chạy dev server</Steps>Tổng kết
Section titled “Tổng kết”- ✅ Svelte tích hợp sẵn trong Starlight
- ✅ Tạo custom components theo nhu cầu
- ✅ Starlight có sẵn Aside, Steps, Tabs, FileTree
- ⚠️ Không dùng
:::syntax- cần đăng ký components
Tài liệu tham khảo: