Interfaz de usuario multiplataforma y móvil · Nuevo recurso

Sistema de diseño Tamagui.

Explora las categorías reales de tokens v5 de Tamagui y sus temas azules claro y oscuro mediante un panel de hábitos completo con componentes nativos, validación, progreso y recuperación de estados vacíos.

Guía de OpenDesign8 capítulos50 entradas de referenciaGuía de aplicación original
01

Vista previa de la interfaz del sistema de diseño de Tamagui

Añade un hábito, registra el progreso, filtra los elementos pendientes y cambia al tema azul.

Crear un tablero de pequeños hábitosAbrir ejemplo completo
Componentes web nativos de Tamagui 2.7.7 con configuración v5 y estado local original. · Referencia de implementación
02

Referencia de diseño del sistema de diseño de Tamagui

Valores exportados por @tamagui/config/v5 y @tamagui/themes en la versión 2.7.7, además de contratos verificados de los componentes nativos.

Tokens de tamaño de v5

Fuente
Nombre / ReglaValor / ConfiguraciónUso
size.$120Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
size.$228Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
size.$336Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
size.$444Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
size.$552Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
size.$664Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.

Tokens de espacio de v5

Fuente
Nombre / ReglaValor / ConfiguraciónUso
space.$12Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$1.54Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$27Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$2.510Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$313Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$3.516Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$418Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$524Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
space.$632Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.

Tokens de radio de v5

Fuente
Nombre / ReglaValor / ConfiguraciónUso
radius.00Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
radius.13Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
radius.25Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
radius.37Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
radius.49Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
radius.510Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.
radius.616Valor real de configuración de v5. La misma etiqueta numérica de token tiene un significado distinto para tamaño, espacio y radio; no interpretes $4 como un valor universal en píxeles.

Tema semántico light_blue

Fuente
Nombre / ReglaValor / ConfiguraciónUso
light_blue.backgroundhsla(207, 100%, 98%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
light_blue.backgroundHoverhsla(210, 100%, 99%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
light_blue.backgroundPresshsla(205, 92%, 95%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
light_blue.colorhsla(216, 71%, 23%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
light_blue.borderColorhsla(203, 100%, 92%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
light_blue.borderColorFocushsla(203, 100%, 92%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
light_blue.placeholderColorhsla(206, 100%, 50%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.

Tema semántico dark_blue

Fuente
Nombre / ReglaValor / ConfiguraciónUso
dark_blue.backgroundhsla(218, 39%, 11%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
dark_blue.backgroundHoverhsla(212, 69%, 16%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
dark_blue.backgroundPresshsla(215, 42%, 9%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
dark_blue.colorhsla(205, 100%, 88%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
dark_blue.borderColorhsla(209, 100%, 19%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
dark_blue.borderColorFocushsla(209, 100%, 19%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.
dark_blue.placeholderColorhsla(206, 100%, 50%, 1)Rol semántico resuelto a partir del tema azul de v5. Para los estados de desplazamiento, pulsación o activación, el componente puede seleccionar un tema secundario más específico.

Roles de la pila tipográfica del sistema

Fuente
Nombre / ReglaValor / ConfiguraciónUso
body.family-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serifLa pila del sistema de v5 no requiere solicitudes a fuentes remotas.
body.$213px / 20pxEl tamaño y la altura de línea forman pares de roles tipográficos, independientes del token de tamaño del componente que tenga la misma etiqueta.
body.$314px / 21pxEl tamaño y la altura de línea forman pares de roles tipográficos, independientes del token de tamaño del componente que tenga la misma etiqueta.
body.$415px / 23pxEl tamaño y la altura de línea forman pares de roles tipográficos, independientes del token de tamaño del componente que tenga la misma etiqueta.
body.$516px / 24pxEl tamaño y la altura de línea forman pares de roles tipográficos, independientes del token de tamaño del componente que tenga la misma etiqueta.
body.$618px / 27pxEl tamaño y la altura de línea forman pares de roles tipográficos, independientes del token de tamaño del componente que tenga la misma etiqueta.
body.$826px / 38pxEl tamaño y la altura de línea forman pares de roles tipográficos, independientes del token de tamaño del componente que tenga la misma etiqueta.

Contratos de composición nativa

Fuente
Nombre / ReglaValor / ConfiguraciónUso
createTamaguidefaultConfig from @tamagui/config/v5Una instancia de configuración fuera de React; getCSS() proporciona el tema web CSS.
TamaguiProviderconfig + defaultThemeLa aplicación elige entre claro y oscuro sin alterar el estado del tablero.
Themename="blue"Resuelve el tema secundario azul de la apariencia actual.
Checkboxchecked + onCheckedChangeEl tablero considera completado solo el valor === true; un estado indeterminado no cuenta como completado.
Inputvalue + onChangeTextBorrador controlado, validación tras eliminar espacios y gestión explícita de duplicados.
Progressvalue from 0 to 100El indicador se calcula dividiendo el número de elementos completados entre el total de filas.
YStack / XStackdirectional layout with token gapMantén el diseño de lectura adaptable sin una hoja de estilos de imitación aparte.
03

Guía completa del sistema de diseño Tamagui

Una guía práctica para elegir, aplicar y revisar este sistema en una interfaz real.

DESIGN-tamagui.md

Orientación completa, un punto de partida para la implementación y enlaces al código fuente.

Descargar la guía

Configuración versionada y CSS del sistema de diseño Tamagui

Usa el ajuste preestablecido con nombre v5

Este ejemplo fija tamagui y @tamagui/config en la versión 2.7.7 e importa defaultConfig desde @tamagui/config/v5. El nombre de la configuración es v5; no corresponde a la versión principal del paquete npm. Confundir esos dos números llevaría a indicar un comando de instalación incorrecto. createTamagui se ejecuta una sola vez, fuera del componente, y su CSS generado se inserta antes de renderizar el tablero, para que las variables del tema y los estilos nativos tengan una definición real para la web.

De esta guía de OpenDesign

Haz explícita la pequeña modificación de configuración

El código fuente proporcionado establece onlyAllowShorthands en false porque este ejemplo didáctico usa propiedades extensas y legibles, como padding y backgroundColor. Esa es una decisión de la aplicación sobre el preset. La base v5 no incluye un motor de animación, y este ejemplo no añade uno ni afirma que haya transiciones animadas. El comportamiento sencillo del progreso y las casillas funciona sin añadir una dependencia de animación aparte.

Tokens de tamaño, espacio y radio del sistema de diseño Tamagui

No confundas tokens con etiquetas idénticas

En la configuración v5 fijada, size $4 es 44, space $4 es 18 y radius 4 es 9. Por tanto, no se puede aplicar una misma regla de multiplicación para convertir el tamaño de un componente, la separación del diseño y el radio de una esquina. La referencia enumera cada categoría por separado, y el ejemplo utiliza valores específicos de cada categoría mediante props reales de Tamagui. Esto resulta más útil que una lista de incrementos genéricos de 4px que la configuración no utiliza.

  • size.$4 = 44
  • space.$4 = 18
  • radius.4 = 9
  • fuente del texto principal $4 = 15px con interlineado de 23px

Mantén también separada la escala tipográfica

La fuente del texto principal $4 es de 15px con un interlineado de 23px, mientras que el tamaño del componente $4 sigue siendo 44. v5 proporciona la pila de fuentes del sistema, por lo que no hace falta descargar ninguna tipografía. H1, H2 y Text reciben sus contextos tipográficos nativos; los valores explícitos de fontSize y lineHeight del código fuente definen la jerarquía del tablero original. El ancho exterior de 880px es una decisión de diseño local, no un token global de Tamagui.

Temas semánticos y apariencia del sistema de diseño Tamagui

Combina los temas claro u oscuro con uno secundario azul

TamaguiProvider recibe el valor defaultTheme elegido, y Theme name="blue" resuelve un tema secundario correspondiente. El código fuente usa los roles background, backgroundHover, color y borderColor en lugar de repetir valores hexadecimales literales por todo el árbol de componentes. La tabla recoge los valores reales de light_blue y dark_blue para que se pueda comparar la configuración resuelta, en vez de dar por sentada una única paleta de marca fija.

Conserva el estado del tablero al cambiar la apariencia

La variable dark es independiente de las filas, el borrador de entrada y el filtro. Cambiar la apariencia actualiza los componentes nativos sin alterar el tablero. Los botones y las casillas pueden seleccionar sus propios valores de tema secundario de componente, por lo que su color calculado quizá no coincida con el token de fondo principal. Inspecciona el estado renderizado antes de aplanar la jerarquía en CSS personalizados.

Casillas y progreso calculado del sistema de diseño Tamagui

Mantén el estado de finalización en una única colección de filas

Cada fila tiene un ID estable, texto legible y un valor booleano done. Checkbox recibe checked y onCheckedChange; solo el valor literal true la marca como completada. Checkbox.Indicator muestra la marca de selección. El texto adyacente y el nombre accesible identifican el mismo hábito, y el tachado refuerza visualmente el estado de finalización. El código fuente no crea un recuento aparte que pueda desincronizarse de las filas.

Calcula el progreso a partir del tablero completo

Validación de borradores y recuperación de duplicados del sistema de diseño Tamagui

Añade un campo de entrada realmente controlado

Input mantiene el borrador actual mediante value y onChangeText. La acción Add habit elimina los espacios sobrantes y rechaza los valores vacíos con un mensaje visible, aria-invalid y una descripción del error. Tras enviar un valor vacío, el foco vuelve al campo de entrada. Una comprobación de duplicados que no distingue entre mayúsculas y minúsculas impide añadir otra fila con el mismo texto y conserva el borrador para que se pueda corregir. Estas reglas pertenecen al tablero original, no a la biblioteca.

Actualiza el tablero solo después de añadir un elemento válido

Un borrador válido añade una fila nueva sin completar, borra el campo de entrada y elimina el error. El denominador del progreso cambia de inmediato porque se calcula a partir de la nueva colección. Añadir un hábito no registra ningún recordatorio ni crea una cuenta. El tablero se guarda deliberadamente en el estado local React, y al recargar el documento se vuelve al ejemplo inicial.

Vistas filtradas y recuperación en estados vacíos del sistema de diseño Tamagui

Deja claro el alcance del filtro

Show unfinished only oculta las filas completadas, pero las conserva en la colección. Si no queda ninguna en esa vista, un estado vacío escrito explica que la lista completa sigue existiendo y ofrece una acción directa para volver a ella. Se trata de un estado vacío significativo, provocado por las decisiones del usuario, no de un interruptor decorativo que intercambia tarjetas de marcador de posición arbitrarias.

Mantén el restablecimiento separado de la apariencia

Restablecer el tablero de ejemplo recupera las tres filas iniciales, borra el borrador y el error, y vuelve a mostrar la lista completa. No modifica la apariencia actual. Como cada cambio es un estado explícito, restablecer no requiere recargar el documento ni descartar el proveedor configurado. La recuperación del tema y del contenido se puede probar por separado.

Tamagui: pilas adaptables y lectura accesible del sistema de diseño

Deja que el contenido de la pila determine la altura

YStack organiza el flujo principal de lectura y XStack alinea los controles del encabezado, las filas de casillas y las acciones. Los grupos de controles se ajustan a varias líneas en lugar de imponer un ancho fijo de escritorio. El contenedor exterior tiene un ancho máximo de 880px y usa el token real de espacio $4 para el relleno. El texto de cada fila puede reducirse y ajustarse a varias líneas, mientras los controles siguen disponibles a 280px y en anchos de prueba mayores.

Prueba la interacción después del reajuste

La comprobación en el navegador añade un hábito, lo marca como completado, filtra la lista y cambia la apariencia antes de medir el desbordamiento. Una captura del diseño inicial por sí sola no revelaría si un error, una etiqueta larga o un estado filtrado rompe la composición estrecha. Se probaron la semántica de las casillas nativas y el texto visible junto con el progreso derivado, en lugar de limitarse a confirmar que estaban presentes y dar por sentado que funcionaban.

Tamagui: compilación completa en el navegador del sistema de diseño

Proporciona el proveedor, CSS y las definiciones de compilación

Los tres archivos proporcionados bastan para el estudio web local. El JSX incluye el proveedor, una configuración, el tema generado CSS y el tablero completo. build.mjs fija el destino web y el entorno de producción, y proporciona un valor alternativo vacío para process.env en otras lecturas de variables de entorno que solo se usan en el navegador. Sin esta última definición, este paquete sencillo puede fallar con el error «process is not defined», aunque compile.

  1. Guarda tamagui.jsx, build.mjs e index.html juntos.
  2. Instala los paquetes fijados React y Tamagui.
  3. Compila y sirve el directorio local.
  4. Prueba las adiciones vacías y duplicadas, la finalización, los filtros, el tema y el restablecimiento.

Mantén separadas la adopción nativa y web

Tamagui: ejemplos de componentes del sistema de diseño

tamagui.jsx

Configuración, CSS generado, componentes nativos y estado completo del tablero.

jsx
import React,{useState} from 'react';import{createRoot}from'react-dom/client';
import{createTamagui,TamaguiProvider,Theme,YStack,XStack,Text,H1,H2,Button,Input,Checkbox,Progress,Separator}from'tamagui';import{defaultConfig}from'@tamagui/config/v5';
const config=createTamagui({...defaultConfig,settings:{...defaultConfig.settings,onlyAllowShorthands:false}});const sheet=document.createElement('style');sheet.textContent=config.getCSS();document.head.append(sheet);
const initial=[{id:1,text:'Read ten pages',done:false},{id:2,text:'Step outside for a break',done:true},{id:3,text:'Write one useful note',done:false}];
function App(){const[dark,setDark]=useState(false),[rows,setRows]=useState(initial),[draft,setDraft]=useState(''),[error,setError]=useState(''),[filter,setFilter]=useState(false);const done=rows.filter(x=>x.done).length;let shown=rows.filter(x=>!filter||!x.done);function add(){let text=draft.trim();if(!text){setError('Write a small habit before adding it.');document.querySelector('#habit-input')?.focus();return}if(rows.some(x=>x.text.toLowerCase()===text.toLowerCase())){setError('That habit is already in this list.');return}setRows([...rows,{id:Date.now(),text,done:false}]);setDraft('');setError('')}return <TamaguiProvider config={config} defaultTheme={dark?'dark':'light'}><Theme name="blue"><YStack backgroundColor="$background" color="$color" padding="$4" gap="$4" maxWidth={880} margin="auto" width="100%" minHeight={0}><XStack justifyContent="space-between" alignItems="center" flexWrap="wrap" gap="$3"><Text fontSize="$2" fontWeight="700">TAMAGUI / ORIGINAL HABIT BOARD</Text><Button size="$3" onPress={()=>setDark(!dark)}>{dark?'Light appearance':'Dark appearance'}</Button></XStack><H1 fontSize="$8" lineHeight="$8">A little progress, every day.</H1><Text fontSize="$4" lineHeight="$5">A local board built with Tamagui 2.7.7 and its v5 blue theme. Your changes stay in this page; no account or daily reminder is connected.</Text><YStack backgroundColor="$backgroundHover" borderWidth={1} borderColor="$borderColor" borderRadius="$4" padding="$4" gap="$3"><XStack justifyContent="space-between" gap="$3" flexWrap="wrap"><H2 fontSize="$5">Today’s small steps</H2><Text id="progress-count" aria-live="polite">{done} of {rows.length} complete</Text></XStack><Progress value={rows.length?done/rows.length*100:0} size="$2" aria-label="Completed habits"><Progress.Indicator animation={undefined}/></Progress><Button size="$3" alignSelf="flex-start" onPress={()=>setFilter(!filter)}>{filter?'Show all habits':'Show unfinished only'}</Button><Separator/>{shown.length?shown.map(row=><XStack key={row.id} gap="$3" alignItems="center" paddingVertical="$2"><Checkbox id={'habit-'+row.id} checked={row.done} onCheckedChange={value=>setRows(rows.map(x=>x.id===row.id?{...x,done:value===true}:x))} aria-label={row.text} size="$4"><Checkbox.Indicator><Text fontWeight="700">✓</Text></Checkbox.Indicator></Checkbox><Text flex={1} fontSize="$4" lineHeight="$5" textDecorationLine={row.done?'line-through':'none'} opacity={row.done?.65:1}>{row.text}</Text></XStack>):<YStack gap="$3"><Text fontWeight="700">Nothing unfinished in this view</Text><Text>All your habits remain in the full list. You can revisit any completed item.</Text><Button onPress={()=>setFilter(false)}>Return to all habits</Button></YStack>}</YStack><YStack gap="$3"><Text htmlFor="habit-input" tag="label" fontWeight="700">Add one small habit</Text><Input id="habit-input" value={draft} onChangeText={v=>{setDraft(v);setError('')}} placeholder="For example, stretch for five minutes" aria-describedby={error?'habit-error':undefined} aria-invalid={!!error} onKeyPress={e=>{if(e.nativeEvent.key==='Enter')add()}}/><Text id="habit-error" color="$color" aria-live="polite">{error}</Text><XStack gap="$3" flexWrap="wrap"><Button theme="active" onPress={add}>Add habit</Button><Button onPress={()=>{setRows(initial);setDraft('');setError('');setFilter(false)}}>Reset sample board</Button></XStack></YStack><Text fontSize="$2" lineHeight="$3">Native Checkbox, Input, Button and Progress components; original board content and state. Theme changes preserve the current board.</Text></YStack></Theme></TamaguiProvider>}
createRoot(document.getElementById('root')).render(<App/>);

Referencia de código

  • Usa juntos estos tres archivos completos.

build.mjs

Definiciones del entorno del navegador que usa el paquete probado.

javascript
import {build} from 'esbuild';
await build({entryPoints:['tamagui.jsx'],bundle:true,minify:true,outfile:'tamagui.bundle.js',define:{'process.env.NODE_ENV':'"production"','process.env.TAMAGUI_TARGET':'"web"','process.env':'{}'}});

Referencia de código

  • Usa juntos estos tres archivos completos.

index.html

Documento raíz independiente e importación del paquete.

HTML
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Small habits board</title><style>body{margin:0}*{box-sizing:border-box}button,input{max-width:100%}</style></head><body><div id="root"></div><script src="./tamagui.bundle.js"></script></body></html>

Referencia de código

  • Usa juntos estos tres archivos completos.
04

Configuración del agente del sistema de diseño Tamagui

Punto de partida para la implementación

Guarda primero los archivos proporcionados y abre http://localhost:8000/. Esta configuración está pensada específicamente para el navegador.

sh
npm init -y
npm install [email protected] [email protected] [email protected] @tamagui/[email protected]
npm install --save-dev esbuild
node build.mjs
python3 -m http.server 8000

Una instrucción para tu proyecto

Instrucción para el agente
Implementa el tablero web completo de hábitos con Tamagui 2.7.7 y el preajuste v5. Mantén diferenciadas las categorías de tokens de tamaño, espacio, radio y fuente; conserva el tema generado CSS, los temas secundarios azul claro y azul oscuro, las casillas controladas, la validación de espacios en blanco y duplicados, el denominador de progreso de todas las filas, la recuperación de la vista de elementos sin terminar y el restablecimiento sin cambiar la apariencia.
05

Fuentes y alcance del sistema de diseño Tamagui

Componentes web Tamagui 2.7.7 reales que usan el preajuste v5. El tablero de hábitos y las reglas de estado son código original de OpenDesign; no están conectados a ninguna cuenta, recordatorio ni comportamiento de dispositivo nativo.