~/pcn $ iniciando_

programaConNosotros

Iniciar sesiónCrear cuenta
  • programaConNosotrosprogramaConNosotrosComunidad · desde 2020
  • Inicio
  • Feed
Actividades
  • Eventos
  • Conversaciones
  • Charlas
  • Podcast
  • Desarrollo
Recursos
  • Cursos
  • Lectura
  • Videos
  • Especialidades
  • Herramientas
  • Proyectos
  • Entrevistas
Comunidad
  • Historia
  • Miembros
  • Logros
  • Galería
  • Setups
  • Partners
  • Changelog
SoporteFeedback

~/desarrollo/diseno

design system · hecho para gente nerd

$ tree ~/desarrollo/diseno

01/29
    1. 01Para quién es
    2. 02Cómo llegamos acá
    3. 03Principios
    4. 04Color
    5. 05Tipografía
    6. 06Espaciado y densidad
    7. 07Bordes y hairlines
    8. 08Movimiento
    9. 09Iconografía
    10. 10Modo oscuro
    11. 11Voz y copy
    12. 12Componentes
  1. ▸componentes/15

    1. 13Button
    2. 14SearchBar
    3. 15Input, Textarea y Select
    4. 16Campo de formulario
    5. 17Checkbox
    6. 18Control segmentado
    7. 19Tabs HUD
    8. 20MarkToggle
    9. 21Badge
    10. 22PageTitle
    11. 23RuledGrid
    12. 24EventRow
    13. 25Menús y selects
    14. 26Dialog
    15. 27Toasts
    1. 28Deuda de diseño
    2. 29Checklist de PR
LEYENDOíndice0%

## Para quién es este website

No es un sitio para cualquier persona. Es para gente súper nerd, apasionada por el software, y está optimizado para que esa gente tenga una gran experiencia.

Esa es la decisión de diseño de la que salen todas las demás. Un sitio para todo el mundo tiene que explicar cada cosa, esconder la densidad y sonar neutro; uno para nerds puede hablar en el idioma de la terminal, mostrar mucha información por pantalla, premiar a quien usa el teclado y esconder detalles para quien los busque (probá ?, ⌘K o gg). El sitio no se achica para gustarle a todo el mundo: quien llega con curiosidad aprende el idioma rápido.

$ pro · moderno · hacky · compacto · al grano

## Cómo llegamos a esta estética

La estética actual no salió de un Figma: se fue encontrando commit a commit, sacando cosas más que agregándolas. Esta es la historia contada desde git log; cada hito linkea a sus commits.

  1. 2024-06-22

    Un Next.js más

    El sitio arranca como cualquier proyecto: shadcn/ui con sus defaults y Geist en lugar de Inter. La única decisión estética que sobrevive hasta hoy es la tipografía.

    1c033fc7cafdd4

  2. 2024-08-21

    La era de las cards

    Toggle de tema claro/oscuro, una card por cada cosa (consejos, miembros activos, crecimiento, eventos, sponsors) y un hero con vortex y texto brillante de Aceternity. Ya aparece la primera pista: las frases motivacionales en fuente de código.

    fdc5f030268ed588e4d01328540f8d9a3ab

  3. 2024-09-13

    Fondo negro

    El tema oscuro pasa a fondo negro puro. Todavía convive con el tema claro, pero el sitio ya se siente mejor de noche.

    df2fa8e

  4. 2025-06-03

    Pico de efectos

    Glass cards, gradientes en cada tarjeta y una flickering card. Mucho brillo y mucho espacio vacío entre cajas: lindo en una captura, lento para escanear.

    fe4385cfe6a09f9222ed0

  5. 2026-04-14

    Menos zoom, solo oscuro

    Se van los zoom-in al pasar el mouse, se fuerza el modo oscuro y desaparece el selector de tema. El título del hero pasa a Geist Mono: la primera vez que la mono es protagonista.

    35c6e885e3dff8b47d7d92a66d42

  6. 2026-09-29

    Rediseño de la home y el sidebar

    Landing y sidebar nuevos, y los logos de los partners sin placas de fondo: el logo flota sobre la pantalla, como un sprite.

    351ee70f6b05d501e822b

  7. 2026-09-30

    El día de la terminal

    El día con más commits de la historia del repo (174). Paleta de fósforo verde sobre negro, Geist Mono para todo lo que es chrome, bordes neutros reemplazados por hairlines verdes, las cards reemplazadas por grillas con líneas compartidas, el breadcrumb reemplazado por un título ~/ruta, tabs tipo HUD, menús que bootean como un CRT, toasts como notificaciones de PCN_OS, el buscador $ grep -i en cada página, 404 de terminal, ⌘K, atajos de vim y PCN OS en pantallas grandes.

    1bf9b5d91101affc02c68a43ab3d7b8f6fca135d1ed29066d949a77464d14b612732443ecffea4dbfb29

  8. 2026-10-01

    Los botones son funciones

    Todo botón con relleno y borde nombra su acción como una llamada: crearEvento();, cancelar();. Los campos de formulario se vuelven prompts de terminal, con caret de bloque que deja ver la letra que tiene abajo.

    34c1cabe8a0365bb322637fdec30

  9. 2026-10-02

    Formularios al milímetro

    Campos que comparten fila alineados exactamente, labels que nunca se parten en dos líneas, botones de guardar pegados al borde inferior en formularios largos y emails transaccionales con la misma estética.

    fa6c82e8d3a776a1d39d607dc210

  10. 2026-10-03

    Compacto y rápido

    El buscador se achica, todos los controles de filtro de un header miden h-8, tabs + búsqueda + filtros entran en una sola fila, las pantallas de carga pasan a skeletons con la forma real de la página y PCN OS suma un modo liviano para computadoras con pocos recursos.

    49a752b0b12366f762e61b4ad1d760ef61a

## Principios de diseño

Ocho reglas, en orden de importancia. Cuando dos chocan, gana la de arriba.

01 Hecho para nerds, no para todo el mundo

El público es gente apasionada por el software. No optimizamos para la persona que nunca abrió una terminal: optimizamos para la que se siente en casa en una. Si un detalle hace sonreír a un dev, vale más que uno que agrada a cualquiera.

✓ sí
~/eventos como título, $ grep -i para buscar, atajos de vim, ⌘K.
✗ no
Heroes de marketing genéricos, stock photos, copy de landing de SaaS.

02 La terminal es la metáfora

Cada pieza de UI tiene un equivalente en una terminal o un editor: prompts, rutas, comentarios, headers de markdown, procesos, notificaciones del sistema. Si no tiene un equivalente, probablemente no hace falta.

✓ sí
## para títulos de sección, // para hints, > para labels, ERR para errores.
✗ no
Íconos decorativos al lado de cada título o emojis como viñetas.

03 Densidad antes que aire

Una persona nerd escanea, no lee de punta a punta. Más información por pantalla, filas en lugar de cards y nada de espacios vacíos entre cajas.

✓ sí
RuledGrid con hairlines compartidas, logos de 36px, descripciones con line-clamp.
✗ no
Grillas de cards con gap-6, sombras y bordes redondeados grandes.

04 Un solo acento

El verde fósforo #04f4be es el único color que llama la atención. Todo lo demás es negro, gris verdoso o una transparencia del mismo verde, así el acento siempre significa algo: interactivo, activo o importante.

✓ sí
pcnGreen y sus opacidades (pcnGreen-200 para líneas, pcnGreen-500 para prompts).
✗ no
Un color por sección, gradientes multicolor, bordes grises neutros.

05 El teclado es ciudadano de primera

Quien vive en un editor espera poder moverse sin mouse. Cada página responde a / para buscar, Esc para limpiar, j/k/gg/G para moverse, [ y ] para saltar entre secciones y ⌘K para ir a cualquier lado.

✓ sí
Mostrar el atajo (<kbd>/</kbd>) dentro del control que lo usa.
✗ no
Interacciones que solo existen con hover o con drag.

06 Microdetalles que se notan

La diferencia entre un sitio con estética hacker y un disfraz está en los detalles: el caret de bloque que deja leer la letra de abajo, los brackets que se abren al hacer hover, el beam que recorre el campo enfocado, el glitch de un error.

✓ sí
Animar estados reales (focus, error, carga) con transform y opacity.
✗ no
Animaciones decorativas sin significado o que bloquean la lectura.

07 Alineado al píxel

Los nerds notan un desfase de 2px. Los controles que comparten fila miden lo mismo (h-8 en headers), los inputs lado a lado arrancan a la misma altura y ningún label se parte en dos líneas.

✓ sí
Labels idénticos en una fila; descripciones y errores siempre debajo del control.
✗ no
Un hint extra arriba de un solo input que lo empuja unos píxeles hacia abajo.

08 Rápido y respetuoso con el hardware

Un dev abre el sitio con veinte pestañas y un IDE corriendo. Skeletons con la forma real de la página, nada de loaders a pantalla completa, prefers-reduced-motion respetado y un modo liviano de PCN OS para máquinas con pocos recursos.

✓ sí
Streaming por sección con su propio skeleton; animaciones solo de transform/opacity.
✗ no
Spinners que tapan toda la pantalla o efectos que corren cada frame sin pausa.

## Color

Negro con un tinte verde y un único acento: el verde fósforo #04f4be. Los tokens semánticos de shadcn viven en src/app/globals.css (bloque .dark) y la escala pcnGreen en tailwind.config.ts. Los valores de abajo se leen en vivo de las variables CSS de esta página.

### Tokens semánticos

--background

…

fondo de toda la pantalla

--foreground

…

texto principal

--card

…

paneles y popovers

--primary

…

acento, ring de foco

--secondary

…

botón secondary

--secondary-foreground

…

texto sobre secondary

--muted

…

fondos apagados

--muted-foreground

…

meta y descripciones

--accent

…

item resaltado

--accent-foreground

…

texto resaltado

--border

…

borde por defecto

--input

…

borde de campos

--destructive

…

errores y borrar

### Escala pcnGreen: un color, diez opacidades

En lugar de tonos más claros u oscuros, la escala es el mismo verde con más o menos alfa: sobre negro se lee como fósforo más o menos encendido y nunca desentona.

pcnGreen-50

…

fondos muy sutiles

pcnGreen-100

…

fondo de badge, skeleton

pcnGreen-200

…

hairlines

pcnGreen-300

…

bordes de badges

pcnGreen-400

…

borde de paneles y menús

pcnGreen-500

…

prompts: $ ## > ›

pcnGreen-600

…

texto de prompt

pcnGreen-700

…

texto secundario verde

pcnGreen-800

…

labels

pcnGreen-900

…

texto de botón outline

pcnGreen

…

acento puro #04f4be

### Los otros colores

red-500 / red-400
Errores, borrar y el badge "En curso". Nunca decorativo.
amber-400
Advertencias (toasts y avisos de cupo).
pcnPurple
Herencia de la marca original; queda en un puñado de lugares y no se usa en UI nueva.
Marcas de terceros
Logos y colores de YouTube, partners, etc. solo dentro de su propio contexto.

## Tipografía

Geist es la única familia del sitio: font-sans (Geist Sans) para leer y font-mono (Geist Mono) para todo lo que es chrome de terminal: títulos, labels, botones, meta, fechas y campos. font-serif está remapeada a Geist Sans para que nunca entre otra familia.

font-sans · Geist Sans

Una comunidad de gente que programa, comparte lo que aprende y se junta a hacer cosas. El cuerpo de texto se lee cómodo en párrafos largos.

font-mono · Geist Mono

~/eventos $ grep -i meetup
crearEvento(); 0O 1lI {} => !=

text-xl · 20px~/programaConNosotrosPageTitle (~/ruta)
text-base · 16px~/programaConNosotrosTítulo de un dialog, nombre de evento
text-sm · 14pxProgramá con nosotrosCuerpo de texto y títulos de sección (##)
text-[13px] · 13px~/programaConNosotrosTexto dentro de campos y menús
text-xs · 12pxProgramá con nosotrosDescripciones, meta, mensajes de error
text-[11px] · 11px~/programaConNosotrosLabels (UPPERCASE), badges, fechas
text-[10px] · 10px~/programaConNosotrosTabs HUD, marcas personales, kbd

Pesos: 400 para texto, 500 para controles y 600 (font-semibold) para títulos; nunca bold extremo. Labels y tabs en UPPERCASE con tracking-[0.14em]; el resto en minúscula o como se escribe.

## Espaciado, densidad y alturas

Escala de Tailwind (múltiplos de 4px) usada con disciplina: pocas medidas que se repiten en todo el sitio. Lo más importante es la altura de los controles, porque es lo que hace que una fila se vea prolija.

h-8
Altura de todo control en una fila de header: SearchBar, segmentados, selects, tabs y botones size="sm". Si comparten fila, miden lo mismo.
h-9
Altura por defecto de inputs, select triggers y botones dentro de formularios.
p-3 / p-4
Padding de una celda de RuledGrid (p-3 en listas densas, p-4 en secciones de documentación). Nunca gap entre celdas: la línea es el separador.
gap-2 / gap-3
Separación entre ícono y texto y entre controles de una misma fila.
mb-4
Separación entre el PageTitle y el contenido; el título no lleva barra fija de 64px.

### Una fila de header: todo mide h-8

idioma

## Bordes, hairlines y esquinas

Hairline
1px border-pcnGreen-200 (#04f4be al 20%). Es el separador universal: entre celdas, alrededor de secciones y debajo de los headers.
Líneas compartidas
RuledGrid dibuja el borde superior e izquierdo y cada celda dibuja el inferior y el derecho, así dos celdas vecinas comparten una sola línea.
Radio
--radius es 0.25rem: rounded-sm (≈0px) para casi todo y nada más redondo que rounded-lg (4px). Las pantallas de terminal tienen esquinas rectas.
Brackets en las esquinas
Botones outline, menús, tabs y campos marcan dos o cuatro esquinas con un ángulo verde de 2px, como el visor de un HUD. Al hacer hover los brackets crecen.
Punteado
border-dashed significa "vacío o bloqueado": estados vacíos, campos deshabilitados y separadores internos de los dialogs.
Glow
Las sombras no son grises: son halos verdes (box-glow, text-glow) que solo aparecen en elementos activos o enfocados.

### Líneas compartidas, no cards

✓ RuledGrid

~/eventos
~/charlas
~/galería
~/cursos

✗ cards con gap

eventos
charlas
galería
cursos

## Movimiento

El movimiento cuenta qué está pasando: algo se enfocó, algo falló, algo está cargando. Las animaciones viven en tailwind.config.ts y globals.css.

cta-pulse / cta-shine
El botón primario late suavemente y un reflejo lo cruza cada 3.6s, para que se vea aún en reposo. Se detiene en hover.
field-beam
Un haz de luz recorre el borde inferior del campo enfocado, como un scanner. field-glitch sacude el campo una vez cuando entra en error.
Boot de CRT
Menús, selects y dialogs se abren como un monitor que se enciende: una línea horizontal que se expande y un barrido de arriba abajo.
Caret
El ~/ruta del título y los campos tienen un cursor de bloque que parpadea; en touch se usa el caret nativo.
Reglas
Duraciones de 150 a 300ms, solo transform/opacity/color, animate-pulse para skeletons y todo apagado con prefers-reduced-motion y en PCN OS liviano.

## Iconografía

lucide-react
Una sola familia de íconos, con el stroke por defecto. size-3 en meta y badges, size-3.5/size-4 en botones y filas.
Color
Los íconos heredan el color del texto (text-current) o usan text-pcnGreen cuando marcan algo activo. Nunca íconos multicolor.
Glifos antes que íconos
Cuando un carácter alcanza, se usa el carácter: › en listas, → y ↗ en links, ~ y / en rutas, ## en títulos, [ ] en la tab activa.
Marcas
Redes sociales en monocromo; logos de partners sin placa de fondo y todos al mismo tamaño visual.

## Modo oscuro

Siempre oscuro
El ThemeProvider fuerza theme="dark" desde abril de 2026: no hay selector. Una terminal es oscura y elegir un tema claro no aporta nada al público.
Fondo
Negro con un tinte verde (--background: 160 30% 2.5%), no #000 puro: el fósforo se ve como una pantalla encendida y no como un vacío.
Scanlines
body::after pinta líneas horizontales verdes al 2.5% sobre toda la pantalla. Casi no se ven, pero se sienten.
Tokens claros
El :root mantiene los tokens claros de shadcn por compatibilidad; ninguna pantalla los usa, así que no hace falta diseñar para ellos.
Selección y scrollbars
El texto seleccionado se pinta en verde con letra negra y los scrollbars son finos, verdes y rectos.

## Voz y copy

Botones como funciones
Todo botón con relleno o borde se escribe como una llamada en camelCase: crearEvento();, subir();, cancelar();. Los estados de carga en minúscula: guardando...
Prompts y rutas
$ antes de un comando o un estado vacío, > antes de un label o un título de dialog, // antes de un hint, ~/ruta como título de página.
Minúsculas
Placeholders y labels cortos en minúscula (título, autor o descripción). La frase completa ("Buscar charlas") va en el aria-label.
Voseo rioplatense
Hablamos como en la comunidad: "sumate", "elegí", "mirá". Directo, sin marketing y sin signos de exclamación de más.
Sin fronteras
PCN nació en Tucumán pero es una comunidad abierta a todo el mundo: el copy no la ata a una ciudad.

### Así sí, así no

✓ crearEvento();

✗ Crear evento

✓ ~/eventos/meetup

✗ Inicio > Eventos > Meetup

✓ $ sin resultados para "cobol"

✗ ¡Ups! No encontramos nada

✓ > HANDLE

✗ Nombre de usuario *

✓ // se ve en tu perfil

✗ Este campo será visible públicamente

✓ ERR ese handle ya está en uso

✗ Error: campo inválido

## Componentes (15)

Los componentes reales del sitio, importados de src/components: no son capturas ni copias. Cada uno muestra sus estados uno al lado del otro; los de interacción (:hover, :focus, :active) se fuerzan copiando las reglas CSS del sitio a un wrapper con data-force-state, como el addon de pseudo-estados de Storybook. Con el selector de estado mirás uno solo y en $ probalo lo usás de verdad.

### Button

src/components/ui/button.tsx ↗

La acción principal es una losa verde que late; la secundaria, un marco oscuro con brackets en las esquinas que se abren al pasar el mouse.

  • ›Con relleno o borde, el texto es una llamada a función en camelCase: crearEvento();
  • ›pcn (= default) para la acción principal: una sola por vista. outline para la secundaria.
  • ›size="sm" (h-8) en headers; default (h-9) en formularios.
  • ›loading reemplaza el ícono por un spinner y el texto por un gerundio: guardando...
  • ›destructive solo para borrar; nunca rojo para otra cosa.
estado
default
:hover
:focus
:active
disabled
loading
pcn
outline
secondary
ghost
destructive
link

### SearchBar

src/components/ui/search-bar.tsx ↗

Toda búsqueda de página es un prompt de shell: $ grep -i. La tecla / la enfoca desde cualquier lado y Esc la limpia.

  • ›Una sola búsqueda por página, siempre este componente: nada de lupa + Input + botón.
  • ›Placeholder corto y en minúscula (título, autor o descripción); el texto completo va en label.
  • ›Mide h-8 como el resto de los controles del header.
  • ›El <kbd>/</kbd> muestra el atajo; con texto se convierte en el botón para limpiar.
estado
vacío
con valor
:focus

$ probalo

### Input, Textarea y Select

src/components/ui/field-surface.ts ↗

Input, Textarea y el trigger del Select comparten .field-surface: texto mono, scanlines, esquinas iluminadas que se encienden con el foco y un haz que recorre el borde.

  • ›Usá siempre estos componentes: el look vive en fieldClassName y en .field-surface (globals.css).
  • ›Error = aria-invalid: esquinas y borde rojos y un glitch de 350ms al entrar en error.
  • ›Deshabilitado o readonly = borde punteado y rayado diagonal, como una terminal bloqueada.
  • ›El caret es un bloque verde que deja ver la letra de abajo (TerminalCaret); en touch, el nativo.
estado
default
:hover
:focus
con valor
error
disabled
Input
Textarea
Select

### Campo de formulario

src/components/ui/form.tsx ↗

Label como prompt (> HANDLE) que se enciende cuando su campo tiene foco, hint con // y error con un tag ERR que entra con un glitch.

  • ›Label corto, en una sola línea: si no entra en la columna, se acorta o la grilla se apila.
  • ›Nada entre el label y el control: hints (FormDescription) y errores (FormMessage) van debajo.
  • ›Los campos que comparten fila arrancan exactamente a la misma altura (probalo abajo).
  • ›Mensajes de error en minúscula y accionables: "elegí un país", no "Campo inválido".
estado
default

se ve en tu perfil

:focus

se ve en tu perfil

error

se ve en tu perfil

ERRese handle ya está en uso

disabled

se ve en tu perfil

$ probalo

como te conoce la comunidad

ERRelegí un país

### Checkbox

src/components/ui/field-surface.ts ↗

Un slot vacío que se llena con un bloque verde brillante al marcarse. Es un <input type="checkbox"> nativo con checkboxClassName.

  • ›Nativo + checkboxClassName (.field-check): accesible sin librerías.
  • ›El label va a la derecha, en mono y minúscula.
estado
default
:hover
:focus
checked
disabled

### Control segmentado

src/components/ui/language-filter.tsx ↗

Filtros de pocas opciones: botones pegados que comparten bordes; el activo se invierte (verde con letra negra).

  • ›El grupo mide h-8 y los botones se estiran: sin py-*.
  • ›Prefijo en gris que nombra el filtro (idioma) y opciones en minúscula.
  • ›aria-pressed en cada opción; role="group" con aria-label en el contenedor.
estado
default
idioma
:hover
idioma
seleccionado
idioma

### Tabs HUD

src/components/ui/tab-styles.tsx ↗

Tira tipo HUD: barra con scanlines, ticks en las esquinas y la tab activa con subrayado brillante y el label entre [ ].

  • ›Labels en UPPERCASE de 10px con tracking amplio; cortos.
  • ›Mide h-7; en una fila de header se lleva a h-8 (className="h-8") y comparte la fila con la búsqueda y los filtros.
  • ›Las tabs que son links (el perfil) usan tabsTriggerClassName con data-state a mano.
estado
default
:hover
:focus
disabled

### MarkToggle

src/components/ui/mark-toggle.tsx ↗

Marcas personales (leído, visto, guardado) que viven arriba de una fila clickeable sin disparar su link.

  • ›Label de una palabra en minúscula y title descriptivo para lectores de pantalla.
  • ›Activo = borde verde, fondo tenue y glow; el ícono se rellena.
estado
default
:hover
:focus
aria-pressed

### Badge

src/components/ui/badge.tsx ↗

Etiquetas de 11px en mono con borde fino: estado, conteos y categorías.

  • ›Texto corto. Los estados vivos (En curso) pueden tener un punto que late.
  • ›destructive solo para estados de error o peligro.
estado
default
:hover
default
typescript
typescript
secondary
typescript
typescript
outline
typescript
typescript
destructive
rechazada
rechazada

### PageTitle

src/components/ui/page-title.tsx ↗

El título de cada página es su ruta: ~/desarrollo/diseno. ~ y cada segmento padre son links, así funciona también como breadcrumb.

  • ›Una sola línea de meta al costado, en minúscula y separada por ·
  • ›Las acciones de la página (botones size="sm") van a la derecha, en el StickyHeader.
  • ›Mientras carga: PageTitleSkeleton, con la misma altura.
estado
default

~/desarrollo/diseno

design system · 15 componentes

loading

### RuledGrid

src/components/ui/ruled-grid.tsx ↗

La pieza central del sistema: listas y catálogos sin cards. La grilla dibuja el borde de arriba y de la izquierda; cada celda, el de abajo y el de la derecha.

  • ›Nunca gap entre celdas: la hairline es el separador.
  • ›Toda la fila es el link (ruledCellClassName en el <Link>); hover = fondo verde al 4%.
  • ›Cargando: RuledGridSkeleton con la misma cantidad de columnas.
  • ›Vacío: una línea punteada que arranca con $, no una ilustración.
estado
default

neovim

editor modal, configurable en Lua

tmux

multiplexor de terminales

ripgrep

grep, pero rápido

:hover

neovim

editor modal, configurable en Lua

tmux

multiplexor de terminales

ripgrep

grep, pero rápido

loading
vacío

$ sin resultados para "cobol"

### EventRow

src/components/events/event-row.tsx ↗

La fila más vista del sitio: flyer chico, fecha en mono, nombre, descripción recortada y lugar, todo dentro de una celda de RuledGrid.

  • ›Thumbnail cuadrado de 64px (más alto en teléfonos, porque los flyers son posters).
  • ›Descripciones con line-clamp: la fila nunca crece por el contenido.
  • ›Al hacer hover el nombre se pone verde y el chevron avanza.
estado
default
Meetup de desarrollo

sáb 14 nov · 19:00

Meetup de desarrollo

Charlas relámpago, pizza y gente que programa. Traé tu notebook.

Blackbox Cowork

:hover
Meetup de desarrollo

sáb 14 nov · 19:00

Meetup de desarrollo

Charlas relámpago, pizza y gente que programa. Traé tu notebook.

Blackbox Cowork

### Menús y selects

src/components/ui/menu-surface.ts ↗

Dropdowns, selects y los menús de PCN OS: un panel de vidrio oscuro con brackets que bootea como un CRT y sus items entrando uno detrás de otro.

  • ›El item resaltado prende una barra brillante a la izquierda y una estela verde.
  • ›Separadores como líneas que se desvanecen en los extremos.
  • ›Items deshabilitados al 50%, sin hover.
abierto

ordenar por

fecha
popularidad
nombre
distancia

$ probalo

### Dialog

src/components/ui/dialog-surface.ts ↗

Un panel de terminal con cuatro esquinas iluminadas y scanlines que se enciende como un CRT. El título es un prompt (>) y los separadores son punteados.

  • ›Título corto en verde con glow; descripción en mono de 12px.
  • ›Footer con la acción principal a la derecha: cancelar(); guardar();
  • ›En formularios largos, el footer queda pegado abajo (dialogFormActionBarClassName).
  • ›Nunca más alto que la pantalla: el panel scrollea, los botones siempre se ven.
abierto

subir foto

jpg o png, hasta 10 MB

$ probalo

### Toasts

src/components/ui/sonner.tsx ↗

Notificaciones de PCN_OS: panel con scanlines, borde izquierdo encendido del color del tipo, un > antes del título y una barra que se consume mientras está en pantalla.

  • ›Arriba a la derecha, con botón para cerrar.
  • ›Verde para éxito e info, ámbar para advertencias, rojo para errores.
  • ›Títulos cortos en minúscula; el detalle va en la descripción.
  • ›Los errores de server actions pasan por actionErrorMessage: producción oculta los mensajes.

$ probalo

## Deuda de diseño

Lo que todavía no sigue estas reglas. Si tocás alguno de estos archivos, es un buen momento para alinearlo.

EmptyState
src/components/empty-state.tsx todavía usa círculos grises de la era de las cards en /herramientas y /software-recomendado. El patrón actual es la línea punteada con $ (EmptyLine).
Skeletons de cards
Algunos skeletons de page-skeletons.tsx (CardListSkeleton, DashboardSkeleton) dibujan cards redondeadas; los nuevos usan RuledGridSkeleton.
Variantes de premio
gold, silver y bronze del Button son de una landing de sponsors que ya no existe y ninguna pantalla las usa: candidatas a borrarse.

## Checklist para una PR de UI

  • [ ]¿La página usa PageTitle con su ~/ruta y una sola línea de meta?
  • [ ]¿Las listas usan RuledGrid (líneas compartidas) en lugar de cards con gap?
  • [ ]¿Todos los controles del header miden h-8 y entran en una fila?
  • [ ]¿La búsqueda es el SearchBar $ grep -i?
  • [ ]¿Los botones con relleno o borde se leen como una función (accion();)?
  • [ ]¿Los inputs que comparten fila arrancan a la misma altura y ningún label se parte?
  • [ ]¿El estado de carga es un skeleton con la forma real (RuledGridSkeleton, PageTitleSkeleton)?
  • [ ]¿El estado vacío es una línea con $ y no una ilustración?
  • [ ]¿Solo se usa el verde como acento y las líneas son pcnGreen-200?
  • [ ]¿Funciona con teclado y respeta prefers-reduced-motion?
  • [ ]¿La PR incluye capturas (pnpm screenshot)?

$ ¿Algo de esto no te cierra? Proponé un cambio.