@svadmin/lite
v0.3.5
Published
SSR-compatible lightweight admin UI for @svadmin — zero client-side JS, works in IE11
Readme
@svadmin/lite
Lightweight, SSR-compatible admin UI for @svadmin.
Zero client-side JavaScript required. Works in IE11 and all modern browsers.
Why?
The main @svadmin/ui package delivers a premium SPA experience using Svelte 5, Tailwind CSS v4, and TanStack.
However, some enterprise/government environments require IE11 compatibility.
@svadmin/lite provides a server-rendered fallback that shares the same DataProvider, AuthProvider, and Resource definitions — only the rendering layer is different.
Features
| Feature | How it works |
|---------|-------------|
| List page | Server-rendered <table> with <a> sort links |
| Detail page | Key-value layout with type-aware formatting |
| Create/Edit | Native <form method="POST"> with server-side validation |
| Delete | <details> confirmation, no JS needed |
| Search | <form method="GET"> with ?q= parameter |
| Pagination | Pure <a> page links |
| Login/Logout | Cookie-based auth via SvelteKit Form Actions |
| Auth Guard | Server hook redirects unauthenticated users |
| UA Detection | Auto-redirect IE11 users to /lite/ routes |
| i18n | Uses @svadmin/core t() translations |
| Multi-level Menu | Config-driven 2/3 level menus via MenuItem[] |
| Print | @media print optimized styles |
Quick Start
1. Install
bun add @svadmin/lite2. Create a list page
// src/routes/lite/posts/+page.server.ts
import { createListLoader, createCrudActions } from '@svadmin/lite';
import { dataProvider, resources } from '$lib/admin';
const postsResource = resources.find(r => r.name === 'posts')!;
export const load = createListLoader(dataProvider, postsResource);
export const actions = createCrudActions(dataProvider, postsResource);<!-- src/routes/lite/posts/+page.svelte -->
<script lang="ts">
export const csr = false; // ← Critical: disable client-side rendering
import { LiteLayout, LiteTable, LitePagination, LiteSearch, LiteAlert } from '@svadmin/lite';
import '@svadmin/lite/src/lite.css';
import { resources } from '$lib/admin';
let { data, form } = $props();
</script>
<LiteLayout resources={resources} currentResource="posts" brandName="My Admin">
<div class="lite-header">
<h1>{data.resource.label}</h1>
<a href="/lite/posts/create" class="lite-btn lite-btn-primary">+ Create</a>
</div>
{#if form?.success}
<LiteAlert type="success" message="Operation completed!" />
{/if}
<LiteSearch value={data.search} />
<LiteTable
records={data.records}
resource={data.resource}
currentSort={data.sort}
currentOrder={data.order}
/>
<LitePagination page={data.page} totalPages={data.totalPages} />
</LiteLayout>2b. Multi-level menu (optional)
Pass a menu prop to LiteLayout to replace the auto-generated flat resource list with a multi-level sidebar:
<script lang="ts">
import type { MenuItem } from '@svadmin/core';
const menu: MenuItem[] = [
{ name: 'home', label: 'Dashboard', href: '/lite' },
{
name: 'content', label: 'Content',
children: [
{ name: 'posts', label: 'Posts', href: '/lite/posts' },
{ name: 'categories', label: 'Categories', href: '/lite/categories' },
],
},
{
name: 'system', label: 'System',
children: [
{ name: 'users', label: 'Users', href: '/lite/users' },
{
name: 'settings', label: 'Settings',
children: [
{ name: 'general', label: 'General', href: '/lite/settings/general' },
{ name: 'security', label: 'Security', href: '/lite/settings/security' },
],
},
],
},
{ name: 'docs', label: 'Documentation', href: 'https://docs.example.com', target: '_blank' },
];
</script>
<LiteLayout {resources} {menu} currentResource="posts" brandName="My Admin">
<!-- ... -->
</LiteLayout>3. Auto-redirect legacy browsers
// src/hooks.server.ts
import { createLegacyRedirectHook } from '@svadmin/lite';
export const handle = createLegacyRedirectHook('/lite');4. Add the <meta> tags for dual-core browsers
<!-- src/app.html -->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta charset="utf-8">
</head>Components
| Component | Description |
|-----------|-------------|
| LiteLayout | Sidebar + main area layout (supports menu prop for multi-level menus) |
| LiteTable | HTML table with sort links and delete confirmation |
| LiteSearch | GET-based search form |
| LitePagination | Page number links |
| LiteForm | Auto-generated form from FieldDefinition[] |
| LiteShow | Record detail/view page |
| LiteLogin | Login form |
| LiteAlert | Success/error notification banner |
Server Utilities
| Function | Description |
|----------|-------------|
| createListLoader(dp, resource) | SvelteKit load function for list pages |
| createDetailLoader(dp, resource) | SvelteKit load function for detail pages |
| createCrudActions(dp, resource) | SvelteKit form actions for create/update/delete |
| createAuthGuard(authProvider) | Server hook for authentication |
| createAuthActions(authProvider) | Login/logout form actions |
| createLegacyRedirectHook() | Auto-redirect IE11 to /lite/ |
| fieldsToZodSchema(fields) | Auto-generate Zod schema for superforms |
CSS
Import @svadmin/lite/src/lite.css in your layout. It's fully self-contained:
- IE11+ baseline (standard flexbox, no CSS variables)
- Custom-styled checkboxes, radios, and selects (no
appearance: noneneeded) - Indigo/Slate color system aligned with
@svadmin/ui - Modern focus rings (
box-shadowbased) - Smooth transitions on all interactive elements
- Multi-layer translucent shadows
- Print-optimized styles
- ~500 lines, ~14KB unminified
Optional: Progressive Enhancement
Copy packages/lite/static/enhance.js to your static folder. This ES5 script adds:
- Auto-close delete confirmation when clicking outside
- Auto-focus first form input
- Unsaved changes warning
100% optional — everything works without it.
License
MIT
