feat(manacore/web): wire TagField, FavoriteButton, ColorPicker into module UIs

Add shared TagField component (ID-based wrapper for TagSelector).
Wire TagField into: calendar EventForm, times EntryForm, cards
CreateDeckModal, contacts detail page. Wire FavoriteButton into
contacts list (replaces inline Star toggle). Add ColorPicker to
cards CreateDeckModal for deck color selection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-02 17:20:46 +02:00
parent 39af8f8480
commit 7ba82472b2
81 changed files with 10403 additions and 600 deletions

View file

@ -41,4 +41,5 @@ export { errorHandler, notFoundHandler } from './error';
export { getBalance, validateCredits, consumeCredits, refundCredits } from './credits';
export type { CreditBalance, CreditValidationResult } from './credits';
export { rateLimitMiddleware } from './rate-limit';
export { requestLogger, initLogger } from './logger';
export type { CurrentUserData, AuthVariables } from './types';

View file

@ -0,0 +1,61 @@
/**
* Structured request logging middleware for Hono servers.
*
* - Generates a unique request ID per request (X-Request-Id header)
* - Logs request/response as JSON lines (in production) or console (in dev)
* - Integrates with @manacore/shared-logger for consistent format
*
* @example
* ```ts
* import { requestLogger } from '@manacore/shared-hono/logger';
* app.use('*', requestLogger());
* ```
*/
import type { MiddlewareHandler } from 'hono';
import { logger as log, configureLogger } from '@manacore/shared-logger';
let _requestIdStore: Map<object, string> | null = null;
function getStore(): Map<object, string> {
if (!_requestIdStore) _requestIdStore = new Map();
return _requestIdStore;
}
/**
* Initialize the Hono logger with a service name.
* Call once at server startup before registering the middleware.
*/
export function initLogger(serviceName: string): void {
configureLogger({ serviceName });
}
/**
* Hono middleware that adds a request ID and logs request + response.
*/
export function requestLogger(): MiddlewareHandler {
return async (c, next) => {
const requestId =
c.req.header('x-request-id') || crypto.randomUUID().slice(0, 8);
c.header('X-Request-Id', requestId);
const method = c.req.method;
const path = c.req.path;
const start = performance.now();
log.info('request', { requestId, method, path });
await next();
const durationMs = Math.round(performance.now() - start);
const status = c.res.status;
if (status >= 500) {
log.error('response', { requestId, method, path, status, durationMs });
} else if (status >= 400) {
log.warn('response', { requestId, method, path, status, durationMs });
} else {
log.info('response', { requestId, method, path, status, durationMs });
}
};
}