feat(web): write descriptions and comments with a visual editor
ts-rich-editor (TipTap) shows the formatting while writing: bold, italic, strike, code, headings, lists, task lists, quotes, code blocks and links, with @ suggesting the project's members and pasted screenshots uploaded as attachments. It reads and writes the same Markdown the API keeps (mentions as @[Name](id), images as attachment:<id>, tables too), so nothing already written changes. Used for comments, replies, editing a comment or a description, a new ticket from the board and the public proposal form; the Markdown hint and the paste directive are gone. List markers sat on a line of their own, and task lists showed a stray bullet, in the editor and when read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,18 +5,18 @@ API repartida en `libs/web/*`.
|
||||
|
||||
## 4.1 Librerías
|
||||
|
||||
| Librería | Contenido |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `web/shared/infrastructure` | Cliente Apollo (`provideGraphql`: HTTP + `graphql-ws`), `API_CONFIG`, puerto `AccessTokenSource` |
|
||||
| `web/shared/ui` | Integración de `@pi/ui` (`providePiUi`), modo oscuro, iconos, `ToastService`, `DrawerService`, `AppShellComponent` |
|
||||
| `web/identity/domain` | `Session`, `CurrentUser`, `AuthConfig` y puertos `AuthGateway`, `ProfileGateway`, `SessionStorage`, `AuthorizationFlow` |
|
||||
| `web/identity/application` | `AuthFacade` (pública); por dentro `AuthStore` y eventos `authPageEvents`, `authApiEvents`, `sessionEvents` |
|
||||
| `web/identity/infrastructure` | `/api/auth/*` (HTTP), `me` (GraphQL), `localStorage`, PKCE con Web Crypto; enlaza `AccessTokenSource` con la `AuthFacade` |
|
||||
| `web/identity/presenters` | Página de login, callback de Pireon, `authGuard` / `guestGuard`, menú de usuario |
|
||||
| `web/tracker/domain` | Modelos, enums, workflow y puertos (`ProjectsGateway`, `IssuesGateway`, `TrackerRealtimeGateway`…) |
|
||||
| `web/tracker/application` | Facades `ProjectsFacade`, `ProjectFacade`, `BoardFacade`, `IssueFacade` y puerto `Notifications`; por dentro, stores y eventos |
|
||||
| `web/tracker/infrastructure` | Adaptadores GraphQL con operaciones tipadas (codegen) |
|
||||
| `web/tracker/presenters` | Páginas: proyectos, tablero, lista, ticket, propuestas, releases, seguimiento, actividad y miembros; `ts-markdown` (texto con formato, saneado con DOMPurify), `ts-bulk-bar`, `ts-vote` |
|
||||
| Librería | Contenido |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `web/shared/infrastructure` | Cliente Apollo (`provideGraphql`: HTTP + `graphql-ws`), `API_CONFIG`, puerto `AccessTokenSource` |
|
||||
| `web/shared/ui` | Integración de `@pi/ui` (`providePiUi`), modo oscuro, iconos, `ToastService`, `DrawerService`, `AppShellComponent` |
|
||||
| `web/identity/domain` | `Session`, `CurrentUser`, `AuthConfig` y puertos `AuthGateway`, `ProfileGateway`, `SessionStorage`, `AuthorizationFlow` |
|
||||
| `web/identity/application` | `AuthFacade` (pública); por dentro `AuthStore` y eventos `authPageEvents`, `authApiEvents`, `sessionEvents` |
|
||||
| `web/identity/infrastructure` | `/api/auth/*` (HTTP), `me` (GraphQL), `localStorage`, PKCE con Web Crypto; enlaza `AccessTokenSource` con la `AuthFacade` |
|
||||
| `web/identity/presenters` | Página de login, callback de Pireon, `authGuard` / `guestGuard`, menú de usuario |
|
||||
| `web/tracker/domain` | Modelos, enums, workflow y puertos (`ProjectsGateway`, `IssuesGateway`, `TrackerRealtimeGateway`…) |
|
||||
| `web/tracker/application` | Facades `ProjectsFacade`, `ProjectFacade`, `BoardFacade`, `IssueFacade` y puerto `Notifications`; por dentro, stores y eventos |
|
||||
| `web/tracker/infrastructure` | Adaptadores GraphQL con operaciones tipadas (codegen) |
|
||||
| `web/tracker/presenters` | Páginas: proyectos, tablero, lista, ticket, propuestas, releases, seguimiento, actividad y miembros; `ts-markdown` (texto con formato, saneado con DOMPurify), `ts-rich-editor`, `ts-bulk-bar`, `ts-vote` |
|
||||
|
||||
## 4.2 Estado: NgRx Signals con eventos
|
||||
|
||||
@@ -127,6 +127,23 @@ hijas de `/p/:key` reciben la misma `ProjectFacade`.
|
||||
Otros contextos también usan la facade: los stores del tracker leen el usuario de `AuthFacade`, y la infraestructura
|
||||
de identidad (`SessionTokenSource`) le pide el token para el cliente GraphQL.
|
||||
|
||||
### Texto con formato
|
||||
|
||||
Descripciones y comentarios se escriben con `ts-rich-editor`, un editor visual sobre
|
||||
[TipTap](https://tiptap.dev) (ProseMirror) que **lee y escribe Markdown**, que es lo que guarda la API:
|
||||
|
||||
- Barra con negrita, cursiva, tachado, código, título, listas, tareas, cita, bloque de código y enlace; Ctrl/Cmd+Enter
|
||||
envía.
|
||||
- `@` sugiere a los miembros del proyecto y escribe la mención como siempre, `@[Nombre](id)` (un lector propio en
|
||||
`rich-text.ts`; la de TipTap usa otro formato).
|
||||
- Pegar una captura la sube como adjunto y la deja como ``; dentro del editor se descarga con
|
||||
la sesión, reintentando unos instantes porque la API tarda en listar el adjunto nuevo.
|
||||
- Entiende también tablas, para que editar un texto antiguo no las pierda (`rich-text.spec.ts` comprueba la ida y
|
||||
vuelta).
|
||||
- Funciona con `[(value)]` y con `[formField]` de los formularios de señales.
|
||||
- Va en un trozo aparte (unos 150 kB comprimido) que solo se descarga en el ticket, el tablero y el formulario de
|
||||
propuestas.
|
||||
|
||||
### Tiempo real y consistencia
|
||||
|
||||
- Cada store se suscribe solo a lo que muestra (`issueChanges(projectId)`, `commentChanges(issueId)`…).
|
||||
|
||||
Reference in New Issue
Block a user