Remix Version โ
HaloLight Remix version is built on React Router 7 (the original Remix team has merged into React Router), featuring TypeScript + Web standards-first full-stack development experience.
Live Preview: https://halolight-remix.h7ml.cn/
GitHub: https://github.com/halolight/halolight-remix
Tech Stack โ
| Technology | Version | Description |
|---|---|---|
| React Router | 7.x | Full-stack routing framework (formerly Remix) |
| React | 19.x | UI framework |
| TypeScript | 5.9 | Type safety |
| Vite | 7.x | Build tool |
| Tailwind CSS | 4.x | Atomic CSS + OKLch |
| Radix UI | latest | Accessible UI primitives |
| Zustand | 5.x | Lightweight state management |
| Recharts | 3.x | Chart visualization |
| Vitest | 4.x | Unit testing |
| Cloudflare Pages | - | Edge deployment |
Core Features โ
- Web Standards: Based on Web Fetch API, FormData, Response
- Nested Routes: Powerful nested layouts and data loading
- Progressive Enhancement: Forms work without JS
- Loader/Action: Elegant server-side data patterns
- Type Safety: Auto-generated route types
- Theme System: 11 skin presets + dark mode
- Multi-tabs: Tab bar + right-click menu management
Directory Structure โ
halolight-remix/
โโโ app/
โ โโโ routes/ # File-based routing
โ โ โโโ _index.tsx # Homepage (dashboard)
โ โ โโโ login.tsx # Login
โ โ โโโ register.tsx # Register
โ โ โโโ forgot-password.tsx # Forgot password
โ โ โโโ reset-password.tsx # Reset password
โ โ โโโ users.tsx # User management
โ โ โโโ settings.tsx # System settings
โ โ โโโ profile.tsx # Profile
โ โ โโโ security.tsx # Security settings
โ โ โโโ analytics.tsx # Data analytics
โ โ โโโ notifications.tsx # Notification center
โ โ โโโ documents.tsx # Document management
โ โ โโโ calendar.tsx # Calendar
โ โ โโโ +types/ # Auto-generated types
โ โโโ components/ # Component library
โ โ โโโ ui/ # Base UI components
โ โ โ โโโ button.tsx
โ โ โ โโโ card.tsx
โ โ โ โโโ dialog.tsx
โ โ โ โโโ dropdown-menu.tsx
โ โ โ โโโ input.tsx
โ โ โ โโโ select.tsx
โ โ โ โโโ table.tsx
โ โ โ โโโ ...
โ โ โโโ layout/ # Layout components
โ โ โ โโโ footer.tsx
โ โ โ โโโ tab-bar.tsx
โ โ โ โโโ quick-settings.tsx
โ โ โโโ auth/ # Auth components
โ โ โ โโโ auth-shell.tsx
โ โ โโโ admin-layout.tsx # Admin layout
โ โ โโโ theme-provider.tsx # Theme provider
โ โโโ hooks/ # React Hooks
โ โ โโโ use-chart-palette.ts
โ โโโ lib/ # Utilities
โ โ โโโ utils.ts # cn() className utility
โ โ โโโ meta.ts # TDK meta info
โ โ โโโ project-info.ts # Project info
โ โโโ stores/ # Zustand state
โ โ โโโ tabs-store.ts # Tabs state
โ โ โโโ ui-settings-store.ts # UI settings state
โ โโโ root.tsx # Root component
โ โโโ routes.ts # Route config
โ โโโ app.css # Global styles
โโโ tests/ # Test files
โ โโโ setup.ts
โ โโโ lib/
โ โโโ stores/
โ โโโ components/
โโโ .github/workflows/ci.yml # CI config
โโโ wrangler.json # Cloudflare config
โโโ vitest.config.ts # Vitest config
โโโ eslint.config.js # ESLint config
โโโ package.jsonQuick Start โ
Installation โ
bash
git clone https://github.com/halolight/halolight-remix.git
cd halolight-remix
pnpm installStart Development โ
bash
pnpm devVisit http://localhost:5173
Production Build โ
bash
pnpm build
pnpm startAvailable Commands โ
bash
pnpm dev # Start dev server
pnpm build # Production build
pnpm start # Start production server
pnpm typecheck # Type checking
pnpm lint # ESLint check
pnpm test # Run tests
pnpm test:run # Run tests once
pnpm test:coverage # Test coverage
pnpm preview # Cloudflare local preview
pnpm deploy # Deploy to CloudflareCore Concepts โ
Route File Conventions โ
React Router 7 uses file-system routing:
_index.tsx โ / (index route)
about.tsx โ /about (static route)
users.tsx โ /users (static route)
users.$id.tsx โ /users/:id (dynamic route)
_layout.tsx โ layout route
$.tsx โ splat routeLoader (Data Loading) โ
tsx
// app/routes/users.tsx
import type { Route } from "./+types/users";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const page = Number(url.searchParams.get("page")) || 1;
const response = await fetch(`/api/users?page=${page}`);
const users = await response.json();
return { users, page };
}
export default function UsersPage({ loaderData }: Route.ComponentProps) {
const { users, page } = loaderData;
return (
<div>
<h1>User List</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}Action (Form Handling) โ
tsx
// app/routes/login.tsx
import type { Route } from "./+types/login";
import { Form, useActionData, useNavigation } from "react-router";
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData();
const email = formData.get("email");
const password = formData.get("password");
// Validation
if (!email || !password) {
return { error: "Please fill in all fields" };
}
// Login logic
const response = await fetch("/api/auth/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: { "Content-Type": "application/json" },
});
if (!response.ok) {
return { error: "Invalid email or password" };
}
// Redirect to homepage
return redirect("/");
}
export default function LoginPage() {
const actionData = useActionData<typeof action>();
const navigation = useNavigation();
const isSubmitting = navigation.state === "submitting";
return (
<Form method="post">
{actionData?.error && (
<p className="text-destructive">{actionData.error}</p>
)}
<input type="email" name="email" placeholder="Email" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Logging in..." : "Login"}
</button>
</Form>
);
}Meta (TDK Meta Info) โ
tsx
// app/routes/users.tsx
import type { Route } from "./+types/users";
import { generateMeta } from "~/lib/meta";
export function meta(): Route.MetaDescriptors {
return generateMeta("/users");
}ts
// app/lib/meta.ts
export const pageMetas: Record<string, PageMeta> = {
"/users": {
title: "User Management",
description: "Manage system user accounts, including creation, editing, and permission configuration",
keywords: ["user management", "account management", "permission configuration"],
},
// ...
};
export function generateMeta(path: string, overrides?: Partial<PageMeta>) {
const meta = pageMetas[path] || { title: "Page", description: "" };
// Return complete meta tag array
}State Management โ
Tabs Store (Tab Management) โ
tsx
// app/stores/tabs-store.ts
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface TabsState {
tabs: Tab[];
activeTabId: string | null;
addTab: (tab: Omit<Tab, "id">) => string;
removeTab: (id: string) => void;
setActiveTab: (id: string) => void;
clearTabs: () => void;
}
export const useTabsStore = create<TabsState>()(
persist(
(set, get) => ({
tabs: [homeTab],
activeTabId: "home",
addTab: (tab) => { /* ... */ },
removeTab: (id) => { /* ... */ },
// ...
}),
{ name: "tabs-storage" }
)
);UI Settings Store (Skin/Layout) โ
tsx
// app/stores/ui-settings-store.ts
export type SkinPreset =
| "default" | "blue" | "emerald" | "amber" | "violet"
| "rose" | "teal" | "slate" | "ocean" | "sunset" | "aurora";
export const useUiSettingsStore = create<UiSettingsState>()(
persist(
(set) => ({
skin: "default",
showFooter: true,
showTabBar: true,
setSkin: (skin) => set({ skin }),
setShowFooter: (visible) => set({ showFooter: visible }),
// ...
}),
{ name: "ui-settings-storage" }
)
);Theme System โ
Skin Presets โ
Supports 11 preset skins, switch via Quick Settings panel:
| Skin | Primary Color |
|---|---|
| Default | Purple |
| Blue | Blue |
| Emerald | Emerald |
| Amber | Amber |
| Violet | Violet |
| Rose | Rose |
| Teal | Teal |
| Slate | Slate |
| Ocean | Ocean Blue |
| Sunset | Sunset Orange |
| Aurora | Aurora |
CSS Variables (OKLch) โ
css
/* app/app.css */
:root {
--background: 100% 0 0;
--foreground: 14.9% 0.017 285.75;
--primary: 51.1% 0.262 276.97;
--primary-foreground: 100% 0 0;
/* ... */
}
[data-skin="ocean"] {
--primary: 54.3% 0.195 240.03;
}
.dark {
--background: 14.9% 0.017 285.75;
--foreground: 98.5% 0 0;
/* ... */
}Page Routes โ
| Path | Page | Description |
|---|---|---|
/ | Dashboard | Data overview + charts |
/login | Login | User login |
/register | Register | User registration |
/forgot-password | Forgot Password | Send reset email |
/reset-password | Reset Password | Set new password |
/users | User Management | User list CRUD |
/settings | System Settings | App configuration |
/profile | Profile | User profile |
/security | Security Settings | Password change, etc. |
/analytics | Data Analytics | Chart display |
/notifications | Notification Center | Message list |
/documents | Document Management | File list |
/calendar | Calendar | Schedule management |
Testing โ
Run Tests โ
bash
pnpm test:run # Single run
pnpm test # Watch mode
pnpm test:coverage # Coverage reportTest Example โ
tsx
// tests/stores/tabs-store.test.ts
import { describe, it, expect, beforeEach } from "vitest";
import { useTabsStore } from "~/stores/tabs-store";
describe("useTabsStore", () => {
beforeEach(() => {
useTabsStore.getState().clearTabs();
});
it("should add new tab", () => {
const { addTab } = useTabsStore.getState();
addTab({ title: "User Management", path: "/users" });
const { tabs } = useTabsStore.getState();
expect(tabs).toHaveLength(2);
});
});Deployment โ
Cloudflare Pages โ
bash
pnpm deployConfigure GitHub Secrets:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
Node.js Server โ
bash
pnpm build
pnpm startDocker โ
dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/build ./build
COPY --from=builder /app/package.json .
RUN npm install --production
EXPOSE 3000
CMD ["npm", "start"]CI/CD โ
The project is configured with complete GitHub Actions CI workflow:
- Lint & Type Check - ESLint + TypeScript checking
- Unit Tests - Vitest unit tests + Codecov coverage
- Build - Production build verification
- Security Audit - Dependency security audit
- Dependency Review - PR dependency change review
Comparison with Other Versions โ
| Feature | Remix Version | Vue Version | Next.js Version |
|---|---|---|---|
| State Management | Zustand | Pinia | Zustand |
| Data Fetching | Loader/Action | TanStack Query | TanStack Query |
| Form Handling | Progressive Enhancement Form | VeeValidate | React Hook Form |
| Server-side | Built-in SSR | Nuxt | App Router |
| Component Library | Radix UI | shadcn-vue | shadcn/ui |
| Routing | File-based routing | Vue Router | App Router |
| Theme | OKLch CSS Variables | OKLch CSS Variables | OKLch CSS Variables |
| Testing | Vitest | Vitest | Vitest |