Task #349: Executive Meetings PDF improvements
- Schema: add `font_color` (hex, default #000000) and `logo_object_path` to `executive_meeting_font_settings`. Pushed via drizzle-kit. - PDF renderer: - Add `fontColor` to PdfFontPrefs (body cells only; header chrome and logo intentionally ignore it to preserve branding). - Add `rowColor` to PdfMeeting and a ROW_COLOR_FILL palette kept in lockstep with the on-screen swatches; deliberately stop painting the legacy `isHighlighted` overlay so the archived PDF reflects editorial state instead of the viewer's transient cursor. - Add optional `logo: Buffer`. Header now reserves a left-anchored logo box and centers the title in the remaining width; bad image bytes log + fall back to the no-logo layout instead of crashing. - API route: - Extend fontSettingsSchema with strict #RRGGBB regex and /^/objects/<id>$/ regex for logoObjectPath. - resolveFontPrefsForUser now returns { font, logoObjectPath }. - loadLogoBytes downloads the brand asset via ObjectStorageService. - Logo only writable on the global-scope row. - PDF labels switched to "قائمة بأسماء حضور الاجتماعات" / "Meeting Attendance List" per the user's printed sample. - Frontend (executive-meetings.tsx): - FontPrefs gains fontColor; FontSettingsResponse.global gains logoObjectPath; DEFAULT_FONT and effectiveFont updated. - buildFontStyle applies fontColor to on-screen rows. - FontSettingsSection: native color picker + hex text input; logo upload (PNG/JPEG) via @workspace/object-storage-web's useUpload, visible only at the global scope for admins. - Locales: AR/EN keys for fontColor + logo.{label,upload,replace, remove,uploading,uploadFailed,globalOnly}. - Tests: existing font-settings roundtrip extended with fontColor; new test rejects malformed fontColor and non-/objects logo paths. Type-check clean for api-server and tx-os; new font-settings tests pass. Other test failures in the suite pre-date this change.
This commit is contained in:
@@ -274,6 +274,16 @@ export const executiveMeetingFontSettingsTable = pgTable(
|
||||
fontSize: integer("font_size").notNull().default(14),
|
||||
fontWeight: varchar("font_weight", { length: 16 }).notNull().default("regular"),
|
||||
alignment: varchar("alignment", { length: 16 }).notNull().default("start"),
|
||||
// Hex color (#RRGGBB) applied to body cell text in both the on-screen
|
||||
// schedule and the generated PDF. Default "#000000" preserves the
|
||||
// historical black-text appearance for rows created before this
|
||||
// column existed. Validated app-side by the regex in
|
||||
// `fontSettingsSchema`.
|
||||
fontColor: varchar("font_color", { length: 16 }).notNull().default("#000000"),
|
||||
// Object-storage path (`/objects/<id>`) of the brand logo embedded
|
||||
// in the top-left of the generated PDF header. NULL = no logo. Only
|
||||
// meaningful on the global-scope row (the per-user row ignores it).
|
||||
logoObjectPath: text("logo_object_path"),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true })
|
||||
.notNull()
|
||||
.defaultNow()
|
||||
|
||||
Reference in New Issue
Block a user