157 lines
4.6 KiB
Markdown
157 lines
4.6 KiB
Markdown
# CLQMS Frontend - Code Style and Conventions
|
|
|
|
## JavaScript/TypeScript
|
|
- **Language**: Plain JavaScript (no TypeScript)
|
|
- **Modules**: Always use `import`/`export` (type: "module" in package.json)
|
|
- **Semicolons**: Use semicolons consistently
|
|
- **Quotes**: Use single quotes for strings
|
|
- **Indentation**: 2 spaces
|
|
- **Trailing commas**: Use in multi-line objects/arrays
|
|
- **JSDoc**: Document all exported functions with JSDoc comments
|
|
|
|
## Svelte Components (Svelte 5 Runes)
|
|
|
|
### Component Structure
|
|
```svelte
|
|
<script>
|
|
// 1. Imports first - group by: Svelte, $lib, external
|
|
import { onMount } from 'svelte';
|
|
import { goto } from '$app/navigation';
|
|
import { auth } from '$lib/stores/auth.js';
|
|
import { login } from '$lib/api/auth.js';
|
|
import { Icon } from 'lucide-svelte';
|
|
|
|
// 2. Props (Svelte 5 runes)
|
|
let { children, data } = $props();
|
|
|
|
// 3. State
|
|
let loading = $state(false);
|
|
let error = $state('');
|
|
|
|
// 4. Derived state (if needed)
|
|
let isValid = $derived(username.length > 0);
|
|
|
|
// 5. Effects
|
|
$effect(() => {
|
|
// side effects
|
|
});
|
|
|
|
// 6. Functions
|
|
function handleSubmit() {
|
|
// implementation
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## Naming Conventions
|
|
- **Components**: PascalCase (`LoginForm.svelte`, `DataTable.svelte`)
|
|
- **Files/Routes**: lowercase with hyphens (`+page.svelte`, `user-profile/`)
|
|
- **Variables**: camelCase (`isLoading`, `userName`)
|
|
- **Constants**: UPPER_SNAKE_CASE (`API_URL`, `STORAGE_KEY`)
|
|
- **Stores**: camelCase, descriptive (`auth`, `valuesets`)
|
|
- **Event handlers**: prefix with `handle` (`handleSubmit`, `handleClick`)
|
|
|
|
## Imports Order
|
|
1. Svelte imports (`svelte`, `$app/*`)
|
|
2. $lib aliases (`$lib/stores/*`, `$lib/api/*`, `$lib/components/*`)
|
|
3. External libraries (`lucide-svelte`)
|
|
4. Relative imports (minimize these, prefer `$lib`)
|
|
|
|
## API Client Pattern
|
|
|
|
### Base Client (src/lib/api/client.js)
|
|
The base client handles JWT token management and 401 redirects automatically.
|
|
|
|
### Feature-Specific API Modules
|
|
```javascript
|
|
// src/lib/api/feature.js - Feature-specific endpoints
|
|
import { apiClient, get, post, put, patch, del } from '$lib/api/client.js';
|
|
|
|
export async function getItem(id) {
|
|
return get(`/api/items/${id}`);
|
|
}
|
|
|
|
export async function createItem(data) {
|
|
return post('/api/items', data);
|
|
}
|
|
```
|
|
|
|
## Form Handling Pattern
|
|
```javascript
|
|
let formData = { name: '', email: '' };
|
|
let errors = {};
|
|
let loading = false;
|
|
|
|
async function handleSubmit() {
|
|
loading = true;
|
|
errors = {};
|
|
|
|
try {
|
|
const result = await createItem(formData);
|
|
|
|
if (result.status === 'error') {
|
|
errors = result.errors || { general: result.message };
|
|
} else {
|
|
// Success - redirect or show message
|
|
}
|
|
} catch (err) {
|
|
errors = { general: err.message || 'An unexpected error occurred' };
|
|
}
|
|
|
|
loading = false;
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
- API errors are thrown with message
|
|
- Use try/catch blocks for async operations
|
|
- Store errors in state for display
|
|
- Toast notifications for user feedback
|
|
|
|
```javascript
|
|
try {
|
|
const result = await api.login(username, password);
|
|
toast.success('Login successful');
|
|
} catch (err) {
|
|
error = err.message || 'An unexpected error occurred';
|
|
console.error('Login failed:', err);
|
|
toast.error('Login failed');
|
|
}
|
|
```
|
|
|
|
## Styling with Tailwind & DaisyUI
|
|
- Use Tailwind utility classes
|
|
- DaisyUI components: `btn`, `card`, `alert`, `input`, `navbar`, `select`
|
|
- Color scheme: `primary` (emerald), `base-100`, `base-200`
|
|
- Custom colors in `app.css` with `@theme`
|
|
|
|
## Authentication Patterns
|
|
- Auth state in `$lib/stores/auth.js`
|
|
- Check auth in layout `onMount` or `+layout.server.js`
|
|
- Redirect to `/login` if unauthenticated
|
|
- API client auto-redirects on 401
|
|
|
|
## LocalStorage
|
|
- Only access in browser: check `browser` from `$app/environment`
|
|
- Use descriptive keys: `auth_token`
|
|
|
|
## Reusable Components
|
|
- **DataTable.svelte**: Sortable, paginated table with actions
|
|
- **Modal.svelte**: Reusable modal for confirmations and forms
|
|
- **SelectDropdown.svelte**: Dropdown populated from ValueSets or API data
|
|
- **Sidebar.svelte**: Navigation sidebar
|
|
- **ToastContainer.svelte**: Toast notifications
|
|
|
|
## SvelteKit Patterns
|
|
- File-based routing with `+page.svelte`, `+layout.svelte`
|
|
- Route groups with `(app)` for protected routes
|
|
- Load data in `+page.js` or `+page.server.js` if needed
|
|
- Use `invalidateAll()` after mutations to refresh data
|
|
|
|
## Code Quality Notes
|
|
- No ESLint or Prettier configured yet
|
|
- No test framework configured yet (plan: Vitest for unit tests, Playwright for E2E)
|
|
- JSDoc comments are required for all exported functions
|
|
- Keep components focused and reusable
|
|
- Extract logic into utility functions when possible
|