@hed-hog/core 0.0.329 → 0.0.330
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/ai.service.d.ts +1 -1
- package/dist/auth/auth.controller.d.ts +23 -23
- package/dist/auth/auth.service.d.ts +41 -41
- package/dist/challenge/challenge.service.d.ts +14 -14
- package/dist/core/system.controller.d.ts +2 -2
- package/dist/core/system.service.d.ts +2 -2
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +7 -4
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +87 -87
- package/dist/dashboard/dashboard/dashboard.service.d.ts +87 -87
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +33 -33
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +33 -33
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +42 -42
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +42 -42
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +12 -12
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +12 -12
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +7 -7
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +7 -7
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +33 -33
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +33 -33
- package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
- package/dist/file/file.controller.d.ts +8 -8
- package/dist/file/file.service.d.ts +18 -18
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/mail/mail.controller.d.ts +15 -15
- package/dist/mail/mail.service.d.ts +15 -15
- package/dist/mail-profile/mail-profile.controller.d.ts +9 -9
- package/dist/mail-profile/mail-profile.service.d.ts +9 -9
- package/dist/mail-sent/mail-sent.controller.d.ts +17 -17
- package/dist/mail-sent/mail-sent.service.d.ts +17 -17
- package/dist/mcp-chat/mcp-chat.controller.d.ts +10 -10
- package/dist/mcp-chat/mcp-chat.service.d.ts +10 -10
- package/dist/menu/menu.controller.d.ts +11 -11
- package/dist/menu/menu.service.d.ts +11 -11
- package/dist/oauth/oauth.service.js +1 -1
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/pdf/components/index.d.ts +57 -0
- package/dist/pdf/components/index.d.ts.map +1 -0
- package/dist/pdf/components/index.js +258 -0
- package/dist/pdf/components/index.js.map +1 -0
- package/dist/pdf/dto/generate-pdf.dto.d.ts +5 -0
- package/dist/pdf/dto/generate-pdf.dto.d.ts.map +1 -0
- package/dist/pdf/dto/generate-pdf.dto.js +27 -0
- package/dist/pdf/dto/generate-pdf.dto.js.map +1 -0
- package/dist/pdf/interfaces/pdf-theme-config.interface.d.ts +10 -0
- package/dist/pdf/interfaces/pdf-theme-config.interface.d.ts.map +1 -0
- package/dist/pdf/interfaces/pdf-theme-config.interface.js +3 -0
- package/dist/pdf/interfaces/pdf-theme-config.interface.js.map +1 -0
- package/dist/pdf/pdf.controller.d.ts +16 -0
- package/dist/pdf/pdf.controller.d.ts.map +1 -0
- package/dist/pdf/pdf.controller.js +100 -0
- package/dist/pdf/pdf.controller.js.map +1 -0
- package/dist/pdf/pdf.module.d.ts +3 -0
- package/dist/pdf/pdf.module.d.ts.map +1 -0
- package/dist/pdf/pdf.module.js +29 -0
- package/dist/pdf/pdf.module.js.map +1 -0
- package/dist/pdf/pdf.service.d.ts +44 -0
- package/dist/pdf/pdf.service.d.ts.map +1 -0
- package/dist/pdf/pdf.service.js +185 -0
- package/dist/pdf/pdf.service.js.map +1 -0
- package/dist/pdf/templates/hcode-institutional.template.d.ts +36 -0
- package/dist/pdf/templates/hcode-institutional.template.d.ts.map +1 -0
- package/dist/pdf/templates/hcode-institutional.template.js +67 -0
- package/dist/pdf/templates/hcode-institutional.template.js.map +1 -0
- package/dist/pdf/themes/hcode.theme.d.ts +25 -0
- package/dist/pdf/themes/hcode.theme.d.ts.map +1 -0
- package/dist/pdf/themes/hcode.theme.js +504 -0
- package/dist/pdf/themes/hcode.theme.js.map +1 -0
- package/dist/profile/profile.controller.d.ts +17 -17
- package/dist/profile/profile.service.d.ts +17 -17
- package/dist/role/role.controller.d.ts +12 -12
- package/dist/role/role.service.d.ts +12 -12
- package/dist/screen/screen.controller.d.ts +3 -3
- package/dist/screen/screen.service.d.ts +3 -3
- package/dist/session/session.controller.d.ts +4 -4
- package/dist/session/session.service.d.ts +12 -12
- package/dist/setting/setting.controller.d.ts +13 -13
- package/dist/setting/setting.service.d.ts +13 -13
- package/dist/user/user.controller.d.ts +24 -24
- package/dist/user/user.service.d.ts +55 -55
- package/hedhog/data/route.yaml +8 -0
- package/hedhog/data/setting_group.yaml +60 -0
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +574 -574
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +5 -9
- package/hedhog/frontend/messages/en.json +2 -0
- package/hedhog/frontend/messages/pt.json +2 -0
- package/package.json +4 -4
- package/src/core.module.ts +7 -4
- package/src/index.ts +9 -6
- package/src/oauth/oauth.service.ts +12 -12
- package/src/pdf/components/index.ts +316 -0
- package/src/pdf/dto/generate-pdf.dto.ts +11 -0
- package/src/pdf/interfaces/pdf-theme-config.interface.ts +10 -0
- package/src/pdf/pdf.controller.ts +86 -0
- package/src/pdf/pdf.module.ts +17 -0
- package/src/pdf/pdf.service.ts +229 -0
- package/src/pdf/templates/hcode-institutional.template.ts +122 -0
- package/src/pdf/themes/hcode.theme.ts +515 -0
|
@@ -212,10 +212,8 @@ function UserCreateSheet({
|
|
|
212
212
|
getSettingValue,
|
|
213
213
|
currentLocaleCode
|
|
214
214
|
);
|
|
215
|
-
return
|
|
216
|
-
|
|
217
|
-
: `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`;
|
|
218
|
-
}, [draftSavedAt, currentLocaleCode, getSettingValue, hasDraft]);
|
|
215
|
+
return t('draftStatus', { relativeLabel, absoluteLabel });
|
|
216
|
+
}, [draftSavedAt, currentLocaleCode, getSettingValue, hasDraft, t]);
|
|
219
217
|
|
|
220
218
|
useEffect(() => {
|
|
221
219
|
if (!open) return;
|
|
@@ -241,7 +239,7 @@ function UserCreateSheet({
|
|
|
241
239
|
e?.response?.data?.message ||
|
|
242
240
|
e?.response?.data?.error ||
|
|
243
241
|
e?.message ||
|
|
244
|
-
'
|
|
242
|
+
t('serverError');
|
|
245
243
|
setFormError(String(msg));
|
|
246
244
|
}
|
|
247
245
|
};
|
|
@@ -453,10 +451,8 @@ function UserEditSheet({
|
|
|
453
451
|
getSettingValue,
|
|
454
452
|
currentLocaleCode
|
|
455
453
|
);
|
|
456
|
-
return
|
|
457
|
-
|
|
458
|
-
: `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`;
|
|
459
|
-
}, [editDraftSavedAt, currentLocaleCode, getSettingValue, hasEditDraft]);
|
|
454
|
+
return t('draftStatus', { relativeLabel, absoluteLabel });
|
|
455
|
+
}, [editDraftSavedAt, currentLocaleCode, getSettingValue, hasEditDraft, t]);
|
|
460
456
|
|
|
461
457
|
useEffect(() => {
|
|
462
458
|
if (!editingUser) return;
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"errorName": "Name must be at least 2 characters",
|
|
128
128
|
"errorEmail": "Invalid email address",
|
|
129
129
|
"errorPassword": "Password must be at least 6 characters",
|
|
130
|
+
"draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
|
|
130
131
|
"userDeletedSuccess": "User deleted successfully.",
|
|
131
132
|
"serverError": "An error occurred. Please try again later.",
|
|
132
133
|
"pictureUpdatedSuccess": "Profile picture updated successfully.",
|
|
@@ -1655,6 +1656,7 @@
|
|
|
1655
1656
|
"noConversation": "Select or create a conversation",
|
|
1656
1657
|
"toolCalled": "Tool called",
|
|
1657
1658
|
"toolResult": "Tool result",
|
|
1659
|
+
"cancel": "Cancel",
|
|
1658
1660
|
"deleteConversation": "Delete",
|
|
1659
1661
|
"emptyConversations": "No conversations yet",
|
|
1660
1662
|
"breadcrumbDashboard": "Dashboard",
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"errorName": "O nome deve ter pelo menos 2 caracteres",
|
|
128
128
|
"errorEmail": "Endereço de e-mail inválido",
|
|
129
129
|
"errorPassword": "A senha deve ter pelo menos 6 caracteres",
|
|
130
|
+
"draftStatus": "Rascunho salvo {relativeLabel} • Último salvamento: {absoluteLabel}",
|
|
130
131
|
"userDeletedSuccess": "Usuário excluído com sucesso.",
|
|
131
132
|
"serverError": "Ocorreu um erro. Por favor, tente novamente mais tarde.",
|
|
132
133
|
"pictureUpdatedSuccess": "Foto de perfil atualizada com sucesso.",
|
|
@@ -1710,6 +1711,7 @@
|
|
|
1710
1711
|
"noConversation": "Selecione ou crie uma conversa",
|
|
1711
1712
|
"toolCalled": "Ferramenta chamada",
|
|
1712
1713
|
"toolResult": "Resultado da ferramenta",
|
|
1714
|
+
"cancel": "Cancelar",
|
|
1713
1715
|
"deleteConversation": "Excluir",
|
|
1714
1716
|
"emptyConversations": "Nenhuma conversa ainda",
|
|
1715
1717
|
"breadcrumbDashboard": "Painel",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.330",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"speakeasy": "^2.0.0",
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
34
|
+
"@hed-hog/api-types": "0.0.1",
|
|
35
|
+
"@hed-hog/api-prisma": "0.0.6",
|
|
34
36
|
"@hed-hog/api": "0.0.8",
|
|
35
37
|
"@hed-hog/api-locale": "0.0.14",
|
|
36
|
-
"@hed-hog/api-pagination": "0.0.7",
|
|
37
38
|
"@hed-hog/api-mail": "0.0.9",
|
|
38
|
-
"@hed-hog/api-
|
|
39
|
-
"@hed-hog/api-prisma": "0.0.6"
|
|
39
|
+
"@hed-hog/api-pagination": "0.0.7"
|
|
40
40
|
},
|
|
41
41
|
"exports": {
|
|
42
42
|
".": {
|
package/src/core.module.ts
CHANGED
|
@@ -8,20 +8,21 @@ import { forwardRef, Global, Inject, MiddlewareConsumer, Module, NestModule, OnM
|
|
|
8
8
|
import { ConfigModule } from '@nestjs/config';
|
|
9
9
|
import { APP_INTERCEPTOR, Reflector } from '@nestjs/core';
|
|
10
10
|
import { AiModule } from './ai/ai.module';
|
|
11
|
-
import { McpModule } from './mcp/mcp.module';
|
|
12
|
-
import { McpChatModule } from './mcp-chat/mcp-chat.module';
|
|
13
11
|
import { AuthModule } from './auth/auth.module';
|
|
14
12
|
import { SystemModule } from './core/system.module';
|
|
15
13
|
import { DashboardModule } from './dashboard/dashboard.module';
|
|
16
14
|
import { FileModule } from './file/file.module';
|
|
17
15
|
import { InstallModule } from './install/install.module';
|
|
18
16
|
import { IntegrationModule } from './integration/integration.module';
|
|
19
|
-
import { MailSentModule } from './mail-sent/mail-sent.module';
|
|
20
17
|
import { MailProfileModule } from './mail-profile/mail-profile.module';
|
|
18
|
+
import { MailSentModule } from './mail-sent/mail-sent.module';
|
|
21
19
|
import { MailModule } from './mail/mail.module';
|
|
20
|
+
import { McpChatModule } from './mcp-chat/mcp-chat.module';
|
|
21
|
+
import { McpModule } from './mcp/mcp.module';
|
|
22
22
|
import { MenuModule } from './menu/menu.module';
|
|
23
23
|
import { LocaleInjectionMiddleware } from './middlewares/locale-injection.middleware';
|
|
24
24
|
import { OAuthModule } from './oauth/oauth.module';
|
|
25
|
+
import { PdfModule } from './pdf/pdf.module';
|
|
25
26
|
import { ProfileModule } from './profile/profile.module';
|
|
26
27
|
import { RoleModule } from './role/role.module';
|
|
27
28
|
import { RouteModule } from './route/route.module';
|
|
@@ -32,11 +33,11 @@ import { SettingModule } from './setting/setting.module';
|
|
|
32
33
|
import { SettingService } from './setting/setting.service';
|
|
33
34
|
import { TaskModule } from './task/task.module';
|
|
34
35
|
import { UserModule } from './user/user.module';
|
|
35
|
-
import { WebhookIntegrationModule } from './webhook-integration/webhook-integration.module';
|
|
36
36
|
import { IsEmailWithSettingsConstraint } from './validators/is-email-with-settings.validator';
|
|
37
37
|
import { IsPinCodeWithSettingConstraint } from './validators/is-pin-code-with-setting.validator';
|
|
38
38
|
import { IsStrongPasswordWithSettingsConstraint } from './validators/is-strong-password-with-settings.validator';
|
|
39
39
|
import { ValidatorServiceLocator } from './validators/service-locator';
|
|
40
|
+
import { WebhookIntegrationModule } from './webhook-integration/webhook-integration.module';
|
|
40
41
|
|
|
41
42
|
@Global()
|
|
42
43
|
@Module({
|
|
@@ -71,6 +72,7 @@ import { ValidatorServiceLocator } from './validators/service-locator';
|
|
|
71
72
|
forwardRef(() => WebhookIntegrationModule),
|
|
72
73
|
forwardRef(() => McpModule),
|
|
73
74
|
forwardRef(() => McpChatModule),
|
|
75
|
+
forwardRef(() => PdfModule),
|
|
74
76
|
],
|
|
75
77
|
exports: [
|
|
76
78
|
UserModule,
|
|
@@ -91,6 +93,7 @@ import { ValidatorServiceLocator } from './validators/service-locator';
|
|
|
91
93
|
IsStrongPasswordWithSettingsConstraint,
|
|
92
94
|
IsEmailWithSettingsConstraint,
|
|
93
95
|
IsPinCodeWithSettingConstraint,
|
|
96
|
+
PdfModule,
|
|
94
97
|
],
|
|
95
98
|
providers: [
|
|
96
99
|
Reflector,
|
package/src/index.ts
CHANGED
|
@@ -19,23 +19,26 @@ export * from './screen/screen.service';
|
|
|
19
19
|
export * from './user/constants/user.constants';
|
|
20
20
|
export * from './user/user.service';
|
|
21
21
|
|
|
22
|
-
export * from './mail/mail.module';
|
|
23
|
-
export * from './mail/mail.service';
|
|
24
22
|
export * from './mail-profile/mail-profile.module';
|
|
25
23
|
export * from './mail-profile/mail-profile.service';
|
|
24
|
+
export * from './mail/mail.module';
|
|
25
|
+
export * from './mail/mail.service';
|
|
26
26
|
|
|
27
27
|
export * from './file/file.module';
|
|
28
28
|
export * from './file/file.service';
|
|
29
|
+
|
|
30
|
+
export * from './pdf/pdf.module';
|
|
31
|
+
export * from './pdf/pdf.service';
|
|
29
32
|
export * from './setting/setting.module';
|
|
30
33
|
export * from './setting/setting.service';
|
|
31
34
|
|
|
32
35
|
export * from './ai/ai.module';
|
|
33
36
|
export * from './ai/ai.service';
|
|
34
37
|
|
|
35
|
-
export * from './webhook-integration/webhook
|
|
38
|
+
export * from './webhook-integration/event-webhook.service';
|
|
36
39
|
export * from './webhook-integration/integration-event-catalog.service';
|
|
40
|
+
export * from './webhook-integration/webhook-integration.module';
|
|
37
41
|
export * from './webhook-integration/webhook-integration.service';
|
|
38
|
-
export * from './webhook-integration/event-webhook.service';
|
|
39
42
|
|
|
40
43
|
// Integration Module
|
|
41
44
|
export * from './integration/integration.module';
|
|
@@ -58,10 +61,10 @@ export * from './validators/is-pin-code-with-setting.validator';
|
|
|
58
61
|
export * from './validators/is-strong-password-with-settings.validator';
|
|
59
62
|
|
|
60
63
|
// MCP Module
|
|
61
|
-
export * from './mcp/mcp.module';
|
|
62
|
-
export * from './mcp/mcp-registry.service';
|
|
63
64
|
export * from './mcp/decorators/mcp-tool.decorator';
|
|
64
65
|
export * from './mcp/interfaces/mcp-tool-definition.interface';
|
|
66
|
+
export * from './mcp/mcp-registry.service';
|
|
67
|
+
export * from './mcp/mcp.module';
|
|
65
68
|
export * from './mcp/types/mcp-context.type';
|
|
66
69
|
|
|
67
70
|
// Utilities
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { getLocaleText } from '@hed-hog/api-locale';
|
|
2
2
|
import { PrismaService, user_account_provider_52222e2ecb_enum } from '@hed-hog/api-prisma';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
BadRequestException,
|
|
5
|
+
ConflictException,
|
|
6
|
+
Inject,
|
|
7
|
+
Injectable,
|
|
8
|
+
Logger,
|
|
9
|
+
NotFoundException,
|
|
10
|
+
ServiceUnavailableException,
|
|
11
|
+
forwardRef
|
|
12
12
|
} from '@nestjs/common';
|
|
13
13
|
import { AuthService } from '../auth/auth.service';
|
|
14
14
|
import { FileService } from '../file/file.service';
|
|
@@ -21,9 +21,9 @@ import { UserService } from '../user/user.service';
|
|
|
21
21
|
import { OAuthProvider } from './interfaces/OAuthProvider';
|
|
22
22
|
import { OAuthCallbackCoordinatorService } from './oauth-callback-coordinator.service';
|
|
23
23
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
OAuthCallbackAlreadyProcessedError,
|
|
25
|
+
OAuthCallbackInProgressError,
|
|
26
|
+
OAuthProviderException,
|
|
27
27
|
} from './oauth.errors';
|
|
28
28
|
import { FacebookProvider } from './providers/facebook.provider';
|
|
29
29
|
import { GithubProvider } from './providers/github.provider';
|
|
@@ -362,7 +362,7 @@ export class OAuthService {
|
|
|
362
362
|
data: {
|
|
363
363
|
name: profile.name,
|
|
364
364
|
role_user: {
|
|
365
|
-
|
|
365
|
+
create: (await roleIds).map((role) => ({ role_id: role.id })),
|
|
366
366
|
},
|
|
367
367
|
user_identifier: {
|
|
368
368
|
create: {
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { PdfThemeConfig } from '../interfaces/pdf-theme-config.interface';
|
|
2
|
+
import { buildFontImport, buildThemeCss } from '../themes/hcode.theme';
|
|
3
|
+
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Inline SVG icon paths (24×24 viewBox, stroke-width 2.2 — Design System spec)
|
|
6
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
const ICON_PATHS: Record<string, string> = {
|
|
8
|
+
discovery:
|
|
9
|
+
'<circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
10
|
+
'<line x1="16.5" y1="16.5" x2="22" y2="22" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/>',
|
|
11
|
+
strategy:
|
|
12
|
+
'<rect x="3" y="12" width="4" height="9" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
13
|
+
'<rect x="10" y="7" width="4" height="14" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
14
|
+
'<rect x="17" y="3" width="4" height="18" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>',
|
|
15
|
+
governance:
|
|
16
|
+
'<polygon points="12,2 22,7 22,17 12,22 2,17 2,7" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
17
|
+
'<polygon points="12,7 17,9.5 17,14.5 12,17 7,14.5 7,9.5" stroke="currentColor" stroke-width="2.2" fill="none"/>',
|
|
18
|
+
training:
|
|
19
|
+
'<path d="M22 10v6m0 0l-10 5-10-5V10l10 5 10-5z" stroke="currentColor" stroke-width="2.2" fill="none" stroke-linejoin="round"/>',
|
|
20
|
+
curriculum:
|
|
21
|
+
'<rect x="2" y="3" width="20" height="14" rx="2" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
22
|
+
'<line x1="7" y1="8" x2="17" y2="8" stroke="currentColor" stroke-width="2.2"/>' +
|
|
23
|
+
'<line x1="7" y1="12" x2="13" y2="12" stroke="currentColor" stroke-width="2.2"/>',
|
|
24
|
+
agents:
|
|
25
|
+
'<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
26
|
+
'<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
27
|
+
'<line x1="12" y1="3" x2="12" y2="1" stroke="currentColor" stroke-width="2.2"/>' +
|
|
28
|
+
'<line x1="12" y1="23" x2="12" y2="21" stroke="currentColor" stroke-width="2.2"/>' +
|
|
29
|
+
'<line x1="3" y1="12" x2="1" y2="12" stroke="currentColor" stroke-width="2.2"/>' +
|
|
30
|
+
'<line x1="23" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="2.2"/>',
|
|
31
|
+
datasets:
|
|
32
|
+
'<rect x="3" y="3" width="8" height="8" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
33
|
+
'<rect x="13" y="3" width="8" height="8" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
34
|
+
'<rect x="3" y="13" width="8" height="8" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
35
|
+
'<rect x="13" y="13" width="8" height="8" rx="1" stroke="currentColor" stroke-width="2.2" fill="none"/>',
|
|
36
|
+
impact:
|
|
37
|
+
'<polyline points="22,12 18,12 15,21 9,3 6,12 2,12" stroke="currentColor" stroke-width="2.2" fill="none" ' +
|
|
38
|
+
'stroke-linecap="round" stroke-linejoin="round"/>',
|
|
39
|
+
experiment:
|
|
40
|
+
'<path d="M9 3h6M9 3v7L4.5 17A2 2 0 006.4 20h11.2a2 2 0 001.9-3L15 10V3" ' +
|
|
41
|
+
'stroke="currentColor" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',
|
|
42
|
+
default:
|
|
43
|
+
'<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.2" fill="none"/>' +
|
|
44
|
+
'<line x1="12" y1="8" x2="12" y2="12" stroke="currentColor" stroke-width="2.2"/>' +
|
|
45
|
+
'<circle cx="12" cy="16" r="0.8" fill="currentColor"/>',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function inlineSvgIcon(name: string): string {
|
|
49
|
+
const path = ICON_PATHS[name] ?? ICON_PATHS.default;
|
|
50
|
+
return (
|
|
51
|
+
`<svg width="17" height="17" viewBox="0 0 24 24" fill="none" ` +
|
|
52
|
+
`xmlns="http://www.w3.org/2000/svg">${path}</svg>`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
57
|
+
// Logo
|
|
58
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Builds the logo HTML.
|
|
62
|
+
* If the admin has set a pdf-logo URL/data-URI → renders <img>.
|
|
63
|
+
* Otherwise renders the CSS-based wordmark from the Design System spec.
|
|
64
|
+
*/
|
|
65
|
+
export function buildLogoHtml(config: PdfThemeConfig, compact = false): string {
|
|
66
|
+
if (config.logoOverride) {
|
|
67
|
+
const h = compact ? '28px' : '36px';
|
|
68
|
+
return (
|
|
69
|
+
`<img src="${config.logoOverride}" alt="${config.companyName}" ` +
|
|
70
|
+
`style="max-height:${h};max-width:140px;object-fit:contain;">`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (compact) {
|
|
74
|
+
// Header-size lockup
|
|
75
|
+
return `<div style="display:flex;flex-direction:column;gap:2px;">
|
|
76
|
+
<div style="font-family:'Inter',sans-serif;font-weight:300;font-size:22px;letter-spacing:-0.01em;line-height:1;">
|
|
77
|
+
<span style="color:var(--primary)">h</span><span style="color:var(--ink-3)">code</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div style="font-family:'Inter',sans-serif;font-weight:400;font-size:7px;letter-spacing:0.30em;text-transform:uppercase;color:var(--primary);">${config.area.toUpperCase()}</div>
|
|
80
|
+
</div>`;
|
|
81
|
+
}
|
|
82
|
+
return `<div class="lockup">
|
|
83
|
+
<div class="lockup-wordmark">
|
|
84
|
+
<span class="glyph">h</span><span class="wordmark">code</span>
|
|
85
|
+
</div>
|
|
86
|
+
<div class="lockup-area">${config.area.toUpperCase()}</div>
|
|
87
|
+
</div>`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
// Page shell
|
|
92
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
/** Wraps everything in a complete HTML document with fonts + theme CSS. */
|
|
95
|
+
export function pageShell(extraHead: string, body: string, config: PdfThemeConfig): string {
|
|
96
|
+
return `<!DOCTYPE html>
|
|
97
|
+
<html lang="pt-BR">
|
|
98
|
+
<head>
|
|
99
|
+
<meta charset="UTF-8">
|
|
100
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
101
|
+
${buildFontImport()}
|
|
102
|
+
${buildThemeCss(config)}
|
|
103
|
+
${extraHead}
|
|
104
|
+
</head>
|
|
105
|
+
<body>
|
|
106
|
+
${body}
|
|
107
|
+
</body>
|
|
108
|
+
</html>`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
112
|
+
// Cover page
|
|
113
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
export interface CoverPageData {
|
|
116
|
+
title: string;
|
|
117
|
+
subtitle?: string;
|
|
118
|
+
/** defaults to current date formatted */
|
|
119
|
+
dateLabel?: string;
|
|
120
|
+
/** defaults to "HCODE · CNPJ 24.700.731/0001-08" */
|
|
121
|
+
bottomMeta?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Full-bleed A4 cover with Design System two-column layout. */
|
|
125
|
+
export function coverPage(config: PdfThemeConfig, data: CoverPageData): string {
|
|
126
|
+
const date =
|
|
127
|
+
data.dateLabel ??
|
|
128
|
+
new Date()
|
|
129
|
+
.toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' })
|
|
130
|
+
.toUpperCase();
|
|
131
|
+
|
|
132
|
+
const areas = [
|
|
133
|
+
{ num: '01', label: 'CONSULTING' },
|
|
134
|
+
{ num: '02', label: 'TRAINING' },
|
|
135
|
+
{ num: '03', label: 'RESEARCH' },
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
return `<div class="cover">
|
|
139
|
+
<!-- LEFT: white, content -->
|
|
140
|
+
<div class="cover-left">
|
|
141
|
+
<div>
|
|
142
|
+
<div class="t-meta" style="margin-bottom:40px;">DESIGN SYSTEM · V1.0 · ${date}</div>
|
|
143
|
+
${buildLogoHtml(config)}
|
|
144
|
+
<div style="margin-top:32px;margin-bottom:20px;">
|
|
145
|
+
<div class="t-display">${data.title}</div>
|
|
146
|
+
</div>
|
|
147
|
+
${data.subtitle ? `<div class="t-body" style="max-width:340px;font-size:12px;">${data.subtitle}</div>` : ''}
|
|
148
|
+
</div>
|
|
149
|
+
<div class="t-micro">${data.bottomMeta ?? 'HCODE · CNPJ 24.700.731/0001-08'}</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<!-- RIGHT: primary color, glyph + area list -->
|
|
153
|
+
<div class="cover-right">
|
|
154
|
+
<div class="cover-system-label">HCODE / SYSTEM</div>
|
|
155
|
+
<div class="cover-release-label">RELEASE 01</div>
|
|
156
|
+
<div class="cover-right-glyph">h</div>
|
|
157
|
+
<ul class="cover-right-areas">
|
|
158
|
+
${areas
|
|
159
|
+
.map(
|
|
160
|
+
(a) =>
|
|
161
|
+
`<li><span class="num">0${areas.indexOf(a) + 1}</span>${a.label}</li>`,
|
|
162
|
+
)
|
|
163
|
+
.join('')}
|
|
164
|
+
</ul>
|
|
165
|
+
</div>
|
|
166
|
+
</div>`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
170
|
+
// Page header (accent bar + logo row)
|
|
171
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
/** Thin primary-colored bar at the very top of a content page. */
|
|
174
|
+
export function pageAccentBar(): string {
|
|
175
|
+
return `<div class="page-accent-bar"></div>`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Header row: compact logo lockup on the left, page title (meta) on the right.
|
|
179
|
+
* Matches Design System pattern: logo | ● PAGE · TITLE
|
|
180
|
+
*/
|
|
181
|
+
export function pageHeader(config: PdfThemeConfig, pageTitle: string): string {
|
|
182
|
+
return `<div class="page-header">
|
|
183
|
+
${buildLogoHtml(config, true)}
|
|
184
|
+
<div style="display:flex;align-items:center;gap:6px;">
|
|
185
|
+
<span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--primary);flex-shrink:0;"></span>
|
|
186
|
+
<div class="t-meta" style="color:var(--ink-3);">${pageTitle.toUpperCase()}</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
192
|
+
// Section header
|
|
193
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
/** Eyebrow + H2 title with primary-color left accent bar — Design System spec. */
|
|
196
|
+
export function sectionHeader(eyebrow: string, title: string): string {
|
|
197
|
+
return `<div class="section-header">
|
|
198
|
+
<div class="t-eyebrow">${eyebrow}</div>
|
|
199
|
+
<div class="t-h2">${title}</div>
|
|
200
|
+
</div>`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
204
|
+
// Purpose block
|
|
205
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
206
|
+
|
|
207
|
+
/** Full-width colored block (primary background) with eyebrow, title and body. */
|
|
208
|
+
export function purposeBlock(eyebrow: string, title: string, body: string): string {
|
|
209
|
+
return `<div class="purpose-block no-break">
|
|
210
|
+
<div class="t-eyebrow">${eyebrow}</div>
|
|
211
|
+
<div class="t-h3">${title}</div>
|
|
212
|
+
<div class="t-body">${body}</div>
|
|
213
|
+
</div>`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
217
|
+
// Feature cards
|
|
218
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
export interface FeatureCardData {
|
|
221
|
+
/** Key from the ICON_PATHS map (e.g. "discovery", "strategy") */
|
|
222
|
+
icon?: string;
|
|
223
|
+
title: string;
|
|
224
|
+
description: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** 3-column feature card grid — icon tile + colored title + body. */
|
|
228
|
+
export function featureCards(cards: FeatureCardData[]): string {
|
|
229
|
+
const items = cards
|
|
230
|
+
.map(
|
|
231
|
+
(c) => `<div class="feature-card no-break">
|
|
232
|
+
<div class="feature-card-icon">${inlineSvgIcon(c.icon ?? 'default')}</div>
|
|
233
|
+
<div class="feature-card-title">${c.title}</div>
|
|
234
|
+
<div class="feature-card-desc">${c.description}</div>
|
|
235
|
+
</div>`,
|
|
236
|
+
)
|
|
237
|
+
.join('');
|
|
238
|
+
return `<div class="feature-cards">${items}</div>`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
242
|
+
// Chip
|
|
243
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
244
|
+
|
|
245
|
+
/** Pill chip with area-colored dot — Design System spec. */
|
|
246
|
+
export function chip(label: string): string {
|
|
247
|
+
return `<span class="chip">${label}</span>`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
251
|
+
// Data table
|
|
252
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
/** Responsive data table with page-break-inside:avoid on rows. */
|
|
255
|
+
export function dataTable(headers: string[], rows: string[][]): string {
|
|
256
|
+
const ths = headers.map((h) => `<th>${h}</th>`).join('');
|
|
257
|
+
const trs = rows
|
|
258
|
+
.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join('')}</tr>`)
|
|
259
|
+
.join('');
|
|
260
|
+
return `<table class="data-table">
|
|
261
|
+
<thead><tr>${ths}</tr></thead>
|
|
262
|
+
<tbody>${trs}</tbody>
|
|
263
|
+
</table>`;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
267
|
+
// Metadata block
|
|
268
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
/** 4-column grid of label+value cells with rounded border. */
|
|
271
|
+
export function metadataBlock(items: Array<{ label: string; value: string }>): string {
|
|
272
|
+
const cells = items
|
|
273
|
+
.map(
|
|
274
|
+
(item) => `<div class="metadata-item">
|
|
275
|
+
<div class="metadata-label">${item.label}</div>
|
|
276
|
+
<div class="metadata-value">${item.value}</div>
|
|
277
|
+
</div>`,
|
|
278
|
+
)
|
|
279
|
+
.join('');
|
|
280
|
+
return `<div class="metadata-block">${cells}</div>`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
284
|
+
// Signature area
|
|
285
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
286
|
+
|
|
287
|
+
/** Auto-grid of signature lines with optional name label. */
|
|
288
|
+
export function signatureArea(
|
|
289
|
+
signatories: Array<{ label: string; name?: string }>,
|
|
290
|
+
): string {
|
|
291
|
+
const items = signatories
|
|
292
|
+
.map(
|
|
293
|
+
(s) => `<div class="signature-item">
|
|
294
|
+
<div class="signature-line"></div>
|
|
295
|
+
<div class="signature-label">${s.label}</div>
|
|
296
|
+
${s.name ? `<div class="signature-name">${s.name}</div>` : ''}
|
|
297
|
+
</div>`,
|
|
298
|
+
)
|
|
299
|
+
.join('');
|
|
300
|
+
return `<div class="signature-area">${items}</div>`;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
304
|
+
// Fixed footer (repeats on every PDF page)
|
|
305
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Fixed footer that appears on every page.
|
|
309
|
+
* Left: company + doc label. Right: page counter via CSS counter(page).
|
|
310
|
+
*/
|
|
311
|
+
export function pdfFooter(companyName = 'hcode', docLabel = 'DESIGN SYSTEM V1.0'): string {
|
|
312
|
+
return `<div class="pdf-footer">
|
|
313
|
+
<div class="t-micro">${companyName.toUpperCase()} · ${docLabel}</div>
|
|
314
|
+
<div class="t-micro pdf-footer-page"></div>
|
|
315
|
+
</div>`;
|
|
316
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IsIn, IsOptional } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
export class GeneratePdfDTO {
|
|
4
|
+
@IsOptional()
|
|
5
|
+
@IsIn(['consulting', 'training', 'research'])
|
|
6
|
+
area?: 'consulting' | 'training' | 'research';
|
|
7
|
+
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsIn(['inline', 'attachment'])
|
|
10
|
+
disposition?: 'inline' | 'attachment';
|
|
11
|
+
}
|