clone of repo on github
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

92 lines
3.4 KiB

---
description:
globs: *.svelte
alwaysApply: false
---
# Svelte Style
Observe the the following style guidelines when programming Svelte components or SvelteKit pages:
- Always use idiomatic Svelte 5 syntax and features. Svelte 5 idioms include:
- Runes, such as `$state`, `$derived`, `$effect`, and `$props`.
- Callback props.
- Snippets.
- Avoid using deprecated Svelte 4 syntax and features. Depecrated features include:
- Props declared via `export let`.
- Event handlers attached via the `on:` directive.
- Event dispatchers.
- Component slots.
- Remember that Svelte 5 state is deeply reactive.
- Mutating a state object automatically triggers reactivity in most cases.
- Avoid trying to trigger reactivity by reassigning state variables unless other options have failed.
- Write components in TypeScript, and prefer strong typing for variables, props, and function signatures.
- Limit component logic to rendering concerns. Extract business logic into separate TypeScript modules, and import functions and classes into Svelte components as needed.
- Use PascalCase when naming Svelte components.
- Keep component files under 500 lines, when possible.
## Component Code Organization Example
When writing or editing a Svelte component, organize the code according to the following template:
```
<script lang='ts'>
// Begin the script section with imports.
// Import only what is necessary.
import type { PublicationTree } from '$lib/data_structures/publication_tree';
import { getContext } from 'svelte';
import type { Asciidoctor } from 'asciidoctor';
// Define props immediately after imports.
// Strongly type the props object.
let {
address,
publicationType,
ref,
}: {
address: string,
publicationType: string,
ref: (ref: HTMLElement) => void,
} = $props();
// Import shared state via `getContext` next.
const publicationTree: PublicationTree = getContext('publicationTree');
const asciidoctor: Asciidoctor = getContext('asciidoctor');
// Then define component state.
// Put `$state` definitions first, followed by `$derived`.
// If derived values depend on others, declare them in the order of derivation.
let leafEvent: Promise<NDKEvent | null> = $derived.by(async () =>
await publicationTree.getEvent(address));
// Define any non-reactive variables after the reactive ones.
let sectionRef: HTMLElement;
// Define component logic below any state declarations.
// Component logic may include functions or `$effect` runes.
$effect(() => {
// Some reactive logic...
});
// Lastly, define any lifecycle hooks, such as `onMount`, at the end of the `<script>` block.
onMount(() => {
// Some mount logic...
});
</script>
<!-- Insert any snippets before the component's regular markup. -->
{#snippet contentParagraph(content: string, publicationType: string, isSectionStart: boolean)}
<section class='whitespace-normal publication-leather'>
{@html content}
</section>
{/snippet}
<!-- The component's markup is typically the last code within the component. -->
<section id={address} bind:this={sectionRef} class='publication-leather content-visibility-auto'>
{#await leafEvent}
{@render contentParagraph(leafEvent.content.toString(), publicationType ?? 'article', false)}
{/await}
</section>
<!-- Style blocks, if needed, may be placed at the end of a component. -->
<!-- Since Tailwind is used, style blocks are usually avoided in favor of Tailwind utility classes. -->
```