chore: regla frontend_theming y comandos claude
Nueva regla para usar componentes @fn_library y sistema de temas CSS variables en todos los frontends. Añade directorio de comandos claude. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,569 @@
|
||||
# /frontend — Skill para proyectos frontend
|
||||
|
||||
Eres un arquitecto frontend experto. Esta skill se activa cuando el usuario pide crear un proyecto frontend, una app con UI, un componente nuevo, o una feature frontend. Tu trabajo es garantizar que TODO el frontend se construya usando el sistema de funciones reutilizables del registry y las mejores practicas actuales.
|
||||
|
||||
---
|
||||
|
||||
## PASO 1: Consultar el registry (OBLIGATORIO)
|
||||
|
||||
Antes de escribir una sola linea de codigo, consulta registry.db para saber que componentes, funciones y tipos frontend ya existen:
|
||||
|
||||
```bash
|
||||
# Componentes y funciones frontend disponibles
|
||||
sqlite3 registry.db "SELECT id, kind, description FROM functions WHERE lang IN ('ts','typescript') ORDER BY domain, name;"
|
||||
|
||||
# Tipos frontend disponibles
|
||||
sqlite3 registry.db "SELECT id, algebraic, description FROM types WHERE lang IN ('ts','typescript') ORDER BY domain, name;"
|
||||
|
||||
# Busqueda FTS5 si buscas algo especifico
|
||||
sqlite3 registry.db "SELECT id, kind, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'name:chart* OR description:chart*') ORDER BY name;"
|
||||
```
|
||||
|
||||
Tambien lista los archivos reales en disco ya que no todos estan indexados aun:
|
||||
|
||||
```bash
|
||||
ls frontend/functions/ui/ # Componentes React
|
||||
ls frontend/functions/core/ # Utilidades TS puras
|
||||
ls frontend/types/ # Tipos
|
||||
```
|
||||
|
||||
**REGLA:** Si un componente ya existe en `frontend/functions/ui/` (alias `@fn_library`), USALO. Nunca recrear lo que ya existe.
|
||||
|
||||
---
|
||||
|
||||
## PASO 2: Determinar el tipo de trabajo
|
||||
|
||||
### A) App nueva en `apps/`
|
||||
Ir a → Seccion SCAFFOLD APP
|
||||
|
||||
### B) Componente nuevo para el registry
|
||||
Ir a → Seccion CREAR COMPONENTE
|
||||
|
||||
### C) Feature en app existente
|
||||
Ir a → Seccion CREAR FEATURE
|
||||
|
||||
---
|
||||
|
||||
## SCAFFOLD APP
|
||||
|
||||
Crear la estructura completa de una app frontend nueva en `apps/{nombre}/frontend/`.
|
||||
|
||||
### Estructura obligatoria
|
||||
|
||||
```
|
||||
apps/{nombre}/
|
||||
frontend/
|
||||
package.json
|
||||
vite.config.ts
|
||||
tsconfig.json
|
||||
index.html
|
||||
src/
|
||||
main.tsx # Entry point
|
||||
App.tsx # Root con ThemeProvider + Router
|
||||
app.css # Tokens CSS — NUNCA hardcodear colores
|
||||
features/ # Feature-based co-location
|
||||
{feature}/
|
||||
components/ # Componentes del feature
|
||||
hooks/ # Hooks del feature
|
||||
types.ts # Tipos del feature
|
||||
index.ts # Barrel export publico
|
||||
components/ # Componentes compartidos de esta app (no reutilizables)
|
||||
hooks/ # Hooks compartidos
|
||||
lib/ # Utilidades, API client
|
||||
types/ # Tipos globales de la app
|
||||
```
|
||||
|
||||
### package.json base
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "{nombre}",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "tsc -b && vite build",
|
||||
"preview": "vite preview --host"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.3.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.577.0",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"recharts": "^2.15.0",
|
||||
"tailwind-merge": "^3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.0",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^8.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Agregar dependencias extras segun necesidad:
|
||||
- **Tablas**: `@tanstack/react-table`
|
||||
- **Charts**: `recharts`
|
||||
- **Iconos extra**: `@phosphor-icons/react`
|
||||
- **Forms**: `react-hook-form`, `@hookform/resolvers`, `zod`
|
||||
- **Router**: `react-router` o `@tanstack/react-router`
|
||||
- **State**: `zustand` (client state), `@tanstack/react-query` (server state)
|
||||
- **Wails**: los hooks de Wails ya estan en `@fn_library` (useWailsQuery, useWailsMutation, useWailsStream, useWailsEvent, WailsProvider)
|
||||
|
||||
### vite.config.ts base
|
||||
|
||||
```ts
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, './src'),
|
||||
'@fn_library': resolve(__dirname, '../../../frontend/functions/ui'),
|
||||
},
|
||||
dedupe: ['react', 'react-dom'],
|
||||
},
|
||||
build: {
|
||||
target: 'es2022',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
'react-vendor': ['react', 'react-dom'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### app.css base
|
||||
|
||||
```css
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme inline {
|
||||
--font-sans: 'Geist Variable', ui-sans-serif, system-ui, sans-serif;
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) * 0.6);
|
||||
--radius-md: calc(var(--radius) * 0.8);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) * 1.4);
|
||||
}
|
||||
|
||||
/* Dark theme (default) */
|
||||
:root,
|
||||
[data-theme="dark"] {
|
||||
--background: oklch(8% 0.015 260);
|
||||
--foreground: oklch(95% 0.01 260);
|
||||
--muted: oklch(18% 0.02 260);
|
||||
--muted-foreground: oklch(60% 0.02 260);
|
||||
--border: oklch(15% 0.01 260);
|
||||
--primary: oklch(65% 0.22 260);
|
||||
--primary-foreground: oklch(98% 0.01 260);
|
||||
--secondary: oklch(20% 0.02 260);
|
||||
--secondary-foreground: oklch(95% 0.01 260);
|
||||
--accent: oklch(18% 0.03 260);
|
||||
--accent-foreground: oklch(95% 0.01 260);
|
||||
--destructive: oklch(55% 0.22 25);
|
||||
--destructive-foreground: oklch(98% 0.01 260);
|
||||
--card: oklch(11% 0.015 260);
|
||||
--card-foreground: oklch(95% 0.01 260);
|
||||
--popover: oklch(12% 0.015 260);
|
||||
--popover-foreground: oklch(95% 0.01 260);
|
||||
--ring: oklch(65% 0.22 260);
|
||||
--input: oklch(22% 0.02 260);
|
||||
--radius: 0.5rem;
|
||||
--chart-1: oklch(62% 0.19 260);
|
||||
--chart-2: oklch(65% 0.2 155);
|
||||
--chart-3: oklch(75% 0.18 85);
|
||||
--chart-4: oklch(60% 0.22 25);
|
||||
--chart-5: oklch(60% 0.2 300);
|
||||
}
|
||||
|
||||
/* Light theme */
|
||||
[data-theme="light"] {
|
||||
--background: oklch(99% 0.005 260);
|
||||
--foreground: oklch(15% 0.01 260);
|
||||
--muted: oklch(95% 0.01 260);
|
||||
--muted-foreground: oklch(45% 0.02 260);
|
||||
--border: oklch(90% 0.01 260);
|
||||
--primary: oklch(50% 0.22 260);
|
||||
--primary-foreground: oklch(98% 0.01 260);
|
||||
--secondary: oklch(95% 0.01 260);
|
||||
--secondary-foreground: oklch(20% 0.01 260);
|
||||
--accent: oklch(95% 0.02 260);
|
||||
--accent-foreground: oklch(20% 0.01 260);
|
||||
--destructive: oklch(55% 0.22 25);
|
||||
--destructive-foreground: oklch(98% 0.01 260);
|
||||
--card: oklch(100% 0 0);
|
||||
--card-foreground: oklch(15% 0.01 260);
|
||||
--popover: oklch(100% 0 0);
|
||||
--popover-foreground: oklch(15% 0.01 260);
|
||||
--ring: oklch(50% 0.22 260);
|
||||
--input: oklch(90% 0.01 260);
|
||||
--radius: 0.5rem;
|
||||
--chart-1: oklch(55% 0.22 260);
|
||||
--chart-2: oklch(55% 0.2 155);
|
||||
--chart-3: oklch(65% 0.18 85);
|
||||
--chart-4: oklch(55% 0.22 25);
|
||||
--chart-5: oklch(55% 0.2 300);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### App.tsx base
|
||||
|
||||
```tsx
|
||||
import { ThemeProvider } from '@fn_library'
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ThemeProvider defaultTheme="dark">
|
||||
{/* Router y contenido aqui */}
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Despues del scaffold
|
||||
|
||||
```bash
|
||||
cd apps/{nombre}/frontend && pnpm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CREAR COMPONENTE
|
||||
|
||||
Para componentes nuevos que van al registry en `frontend/functions/`.
|
||||
|
||||
### Reglas de implementacion
|
||||
|
||||
1. **Headless first**: usar `@base-ui/react` como primitivo si el componente es interactivo (dialog, select, tooltip, etc.)
|
||||
2. **CVA para variantes**: SIEMPRE usar `class-variance-authority` para definir variantes
|
||||
3. **cn() para clases**: SIEMPRE usar `cn()` de `frontend/functions/core/cn.ts` para componer classNames
|
||||
4. **CSS variables**: NUNCA hex/rgb/oklch inline en el componente — solo clases Tailwind que mapean a CSS variables (`bg-primary`, `text-muted-foreground`, `border-border`)
|
||||
5. **Props tipadas**: usar `React.ComponentPropsWithoutRef<"element">` para HTML props spreading
|
||||
6. **Accesibilidad**:
|
||||
- Elementos semanticos: `<button>` para acciones, `<a>` para navegacion, `<dialog>` para modales
|
||||
- NUNCA `<div onClick>` para elementos interactivos
|
||||
- `aria-label` o `aria-labelledby` en todo componente interactivo
|
||||
- `aria-invalid` + `aria-describedby` en inputs con error
|
||||
- `role="status"` para loading states
|
||||
- Focus management en modales/popovers
|
||||
7. **Discriminated unions** cuando las props cambian segun variante:
|
||||
|
||||
```tsx
|
||||
type Props = { size?: 'sm' | 'md' | 'lg'; children: React.ReactNode } & (
|
||||
| { variant: 'link'; href: string; onClick?: never }
|
||||
| { variant: 'button'; onClick: () => void; href?: never }
|
||||
)
|
||||
```
|
||||
|
||||
### Patron de archivo .tsx
|
||||
|
||||
```tsx
|
||||
import * as React from 'react'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { cn } from '../core/cn'
|
||||
|
||||
const componentVariants = cva(
|
||||
'base-classes-here', // clases base
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'classes...',
|
||||
secondary: 'classes...',
|
||||
},
|
||||
size: {
|
||||
sm: 'classes...',
|
||||
md: 'classes...',
|
||||
lg: 'classes...',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'md',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
interface ComponentProps
|
||||
extends React.ComponentPropsWithoutRef<'div'>,
|
||||
VariantProps<typeof componentVariants> {
|
||||
// props adicionales con JSDoc
|
||||
/** Descripcion de la prop */
|
||||
customProp?: string
|
||||
}
|
||||
|
||||
const Component = React.forwardRef<HTMLDivElement, ComponentProps>(
|
||||
({ className, variant, size, customProp, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(componentVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Component.displayName = 'Component'
|
||||
|
||||
export { Component, componentVariants }
|
||||
export type { ComponentProps }
|
||||
```
|
||||
|
||||
### Patron de archivo .md
|
||||
|
||||
**IMPORTANTE:** El campo `lang` debe ser `ts` (no `typescript`). El indexer solo reconoce `ts`. Los IDs siguen el formato `{name}_ts_{domain}`.
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: component_name
|
||||
kind: component
|
||||
lang: ts
|
||||
domain: ui
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "ComponentName(props: ComponentProps): JSX.Element"
|
||||
description: "Descripcion concisa de que hace el componente"
|
||||
tags: [component, ui, ...]
|
||||
uses_functions: [cn_ts_core]
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: ["@base-ui/react", "class-variance-authority"]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "frontend/functions/ui/component_name.tsx"
|
||||
props:
|
||||
- name: variant
|
||||
type: "'default' | 'secondary'"
|
||||
required: false
|
||||
description: "Estilo visual"
|
||||
- name: className
|
||||
type: "string"
|
||||
required: false
|
||||
description: "Clases CSS adicionales"
|
||||
emits: []
|
||||
has_state: false
|
||||
framework: react
|
||||
variant: [default, secondary]
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
...codigo de ejemplo...
|
||||
|
||||
## Notas
|
||||
|
||||
...notas relevantes...
|
||||
```
|
||||
|
||||
### Despues de crear
|
||||
|
||||
```bash
|
||||
./fn index && ./fn show {id}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CREAR FEATURE
|
||||
|
||||
Para features dentro de una app existente. Co-location obligatoria.
|
||||
|
||||
### Estructura
|
||||
|
||||
```
|
||||
src/features/{feature_name}/
|
||||
components/
|
||||
FeatureMain.tsx # Componente principal
|
||||
FeatureDetail.tsx # Sub-componentes
|
||||
hooks/
|
||||
useFeatureData.ts # Hooks del feature
|
||||
types.ts # Tipos locales
|
||||
index.ts # Barrel export
|
||||
```
|
||||
|
||||
### Barrel export (index.ts)
|
||||
|
||||
```ts
|
||||
// Solo exportar la API publica del feature
|
||||
export { FeatureMain } from './components/FeatureMain'
|
||||
export { useFeatureData } from './hooks/useFeatureData'
|
||||
export type { FeatureItem, FeatureConfig } from './types'
|
||||
```
|
||||
|
||||
### Patrones de estado obligatorios
|
||||
|
||||
**Server state** (datos de API/backend):
|
||||
```tsx
|
||||
// Con @tanstack/react-query
|
||||
const queryKeys = {
|
||||
all: ['feature'] as const,
|
||||
list: (filters: Filters) => [...queryKeys.all, 'list', filters] as const,
|
||||
detail: (id: string) => [...queryKeys.all, 'detail', id] as const,
|
||||
}
|
||||
|
||||
function useFeatureList(filters: Filters) {
|
||||
return useQuery({
|
||||
queryKey: queryKeys.list(filters),
|
||||
queryFn: () => fetchFeatureList(filters),
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**Client state** (UI state compartido):
|
||||
```tsx
|
||||
// Con Zustand
|
||||
import { create } from 'zustand'
|
||||
|
||||
interface FeatureStore {
|
||||
selectedId: string | null
|
||||
setSelected: (id: string | null) => void
|
||||
}
|
||||
|
||||
const useFeatureStore = create<FeatureStore>((set) => ({
|
||||
selectedId: null,
|
||||
setSelected: (id) => set({ selectedId: id }),
|
||||
}))
|
||||
```
|
||||
|
||||
**Wails** (apps de escritorio):
|
||||
```tsx
|
||||
// Usar hooks del registry
|
||||
import { useWailsQuery, useWailsMutation } from '@fn_library'
|
||||
|
||||
function useFeatureData() {
|
||||
return useWailsQuery('GetFeatureData', [], { staleTime: 60_000 })
|
||||
}
|
||||
```
|
||||
|
||||
### Code splitting por ruta
|
||||
|
||||
```tsx
|
||||
import { lazy, Suspense } from 'react'
|
||||
import { Skeleton } from '@fn_library'
|
||||
|
||||
const FeaturePage = lazy(() => import('./features/feature/components/FeaturePage'))
|
||||
|
||||
function AppRoutes() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/feature" element={
|
||||
<Suspense fallback={<Skeleton className="h-screen w-full" />}>
|
||||
<FeaturePage />
|
||||
</Suspense>
|
||||
} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CHECKLIST DE VALIDACION (ejecutar siempre al final)
|
||||
|
||||
Antes de dar por terminado cualquier trabajo frontend, verificar:
|
||||
|
||||
### Colores y estilos
|
||||
- [ ] CERO colores hardcodeados (no hex, no rgb, no oklch inline en componentes)
|
||||
- [ ] Solo clases Tailwind mapeadas a CSS variables: `bg-primary`, `text-foreground`, `border-border`, etc.
|
||||
- [ ] `cn()` usado para merge de clases en todo componente
|
||||
- [ ] CVA usado para variantes (no condicionales manuales con ternarios)
|
||||
|
||||
### Componentes del registry
|
||||
- [ ] Verificado que no se esta recreando algo que ya existe en `@fn_library` (`frontend/functions/ui/`)
|
||||
- [ ] Componentes de `@fn_library` usados donde aplica: Alert, Badge, Button, Card, Dialog, Input, Label, Select, SimpleSelect, Skeleton, Sparkline, Tabs, Tooltip, FormField, PageHeader, ProgressBar, KPICard, ThemeProvider, DashboardLayout, DataTable, charts (AreaChart, BarChart, LineChart, PieChart, ChartContainer), hooks Wails (useWailsQuery, useWailsMutation, useWailsStream, useWailsEvent)
|
||||
|
||||
### TypeScript
|
||||
- [ ] Props interfaces con `React.ComponentPropsWithoutRef` para HTML spreading
|
||||
- [ ] Discriminated unions donde las props varian segun tipo/variante
|
||||
- [ ] `as const` para arrays literales y config objects
|
||||
- [ ] No `any` — usar `unknown` + type guards si es necesario
|
||||
|
||||
### Accesibilidad
|
||||
- [ ] Elementos semanticos (button, a, dialog — no div onClick)
|
||||
- [ ] `aria-label` en botones de solo icono
|
||||
- [ ] `aria-invalid` + `aria-describedby` en inputs con validacion
|
||||
- [ ] Focus trap en modales y popovers
|
||||
- [ ] `prefers-reduced-motion` respetado (ya en app.css base)
|
||||
|
||||
### Performance
|
||||
- [ ] Lazy loading en rutas (`React.lazy` + `Suspense`)
|
||||
- [ ] `manualChunks` en vite.config para vendor splitting
|
||||
- [ ] Sin barrel exports profundos que maten tree-shaking
|
||||
- [ ] Listas largas virtualizadas si >100 items
|
||||
|
||||
### Estructura
|
||||
- [ ] Features co-located: componente + hook + tipos + barrel en el mismo directorio
|
||||
- [ ] Un `index.ts` por feature con API publica explicita
|
||||
- [ ] Componentes reutilizables de la app en `src/components/`
|
||||
- [ ] Tipos compartidos en `src/types/`
|
||||
|
||||
---
|
||||
|
||||
## ANTI-PATRONES (nunca hacer)
|
||||
|
||||
1. **`<div onClick={...}>`** → usar `<button>` o Base-UI primitivo
|
||||
2. **`style={{ color: '#3b82f6' }}`** → usar `className="text-primary"`
|
||||
3. **`import Button from './MyButton'`** cuando existe en la lib → usar `import { Button } from '@fn_library'`
|
||||
4. **Estado global para todo** → segmentar: server state (React Query), client state (Zustand), form state (React Hook Form), URL state (search params)
|
||||
5. **`index.ts` en la raiz de `src/`** que re-exporta todo → mata tree-shaking
|
||||
6. **`// @ts-ignore`** → arreglar el tipo
|
||||
7. **CSS-in-JS runtime** (styled-components, emotion) → usar Tailwind
|
||||
8. **Instalar shadcn/ui como dependencia** → los componentes ya estan en el registry, usar `@fn_library`
|
||||
9. **Crear utilidades que ya existen**: `cn()`, `getSeriesColor()`, `ChartContainer`, `ThemeProvider` ya estan en `@fn_library`
|
||||
10. **Colores de chart hardcodeados** → usar `--chart-1` a `--chart-5` o `getSeriesColor()`
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -16,3 +16,4 @@ Reglas operativas del proyecto. Cada archivo es una regla independiente.
|
||||
| 10 | [apps_vs_functions.md](apps_vs_functions.md) | Codigo reutilizable en functions/, no reutilizable en apps/ |
|
||||
| 11 | [sources.md](sources.md) | Extraccion de funciones desde repos externos |
|
||||
| 12 | [notebook_collaboration.md](notebook_collaboration.md) | Colaboración en notebooks Jupyter via funciones del registry |
|
||||
| 13 | [frontend_theming.md](frontend_theming.md) | Componentes propios y sistema de temas en frontends |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
En todos los frontends se usan los componentes de `@fn_library` (alias a `frontend/functions/ui/`) antes que elementos HTML nativos o librerias externas.
|
||||
|
||||
En todos los frontends se usa el sistema de temas basado en CSS variables (`--background`, `--foreground`, `--input`, `--border`, `--popover`, etc.) definidas en `app.css`. Los componentes deben leer estas variables para adaptarse al tema activo. Nunca hardcodear colores.
|
||||
Reference in New Issue
Block a user