;
+ containerId?: string;
+}) {
const { resolvedTheme } = useTheme();
+ const mountedRef = useRef(false);
useEffect(() => {
+ mountedRef.current = true;
+ return () => {
+ mountedRef.current = false;
+ };
+ }, []);
- const container = containerRef.current;
- if (!container) return;
+ useEffect(() => {
+ if (!mountedRef.current) return;
- let active = true;
- const injectedDivs: HTMLDivElement[] = [];
-
- const renderDiagrams = async () => {
- try {
- const preElements = Array.from(container.querySelectorAll('pre')).filter((pre) => {
- const code = pre.querySelector('code');
- return code && (code.classList.contains('language-mermaid') || code.classList.contains('lang-mermaid'));
- });
-
- if (preElements.length === 0) return;
-
- const mermaid = (await import('mermaid')).default;
-
- const isDark = resolvedTheme === 'dark';
- mermaid.initialize({
- startOnLoad: false,
- theme: isDark ? 'dark' : 'default',
- securityLevel: 'loose',
- fontFamily: 'var(--font-geist-sans), sans-serif',
- themeVariables: {
- fontFamily: 'var(--font-geist-sans), sans-serif',
- primaryColor: isDark ? '#1e293b' : '#f1f5f9',
- primaryTextColor: isDark ? '#f8fafc' : '#020617',
- primaryBorderColor: isDark ? '#334155' : '#cbd5e1',
- lineColor: isDark ? '#64748b' : '#94a3b8',
- secondaryColor: isDark ? '#0f172a' : '#f8fafc',
- tertiaryColor: isDark ? '#1e293b' : '#f1f5f9',
- },
- });
-
- for (let i = 0; i < preElements.length; i++) {
- if (!active) break;
-
- const pre = preElements[i];
- const codeEl = pre.querySelector('code');
- if (!codeEl) continue;
-
- let rawCode = pre.getAttribute('data-mermaid-code');
- if (!rawCode) {
- rawCode = codeEl.textContent || '';
- pre.setAttribute('data-mermaid-code', rawCode);
- }
+ let container: HTMLElement | null = null;
+ if (containerRef && containerRef.current) {
+ container = containerRef.current;
+ } else if (containerId) {
+ container = document.getElementById(containerId);
+ }
+
+ if (!container) return;
+ // Find all mermaid code blocks.
+ // Shiki wraps code in .
+ // Alternatively, without shiki, marked might output .
+ // We will look for code.language-mermaid.
+ const mermaidNodes = container.querySelectorAll('pre code.language-mermaid, pre.shiki code.language-mermaid');
+
+ if (mermaidNodes.length === 0) return;
+
+ let isActive = true;
+
+ async function renderDiagrams() {
+ // Dynamically import mermaid to avoid bloat on pages without diagrams
+ const mermaidModule = await import('mermaid');
+ const mermaid = mermaidModule.default;
+
+ if (!isActive) return;
+
+ // Ensure zero rounding rule is applied in mermaid configuration
+ mermaid.initialize({
+ startOnLoad: false,
+ theme: resolvedTheme === 'dark' ? 'dark' : 'default',
+ securityLevel: 'loose',
+ fontFamily: 'inherit',
+ themeVariables: {
+ // You can tweak colors here to match the Acite design system if needed
+ }
+ });
- const wrapperId = pre.getAttribute('data-mermaid-wrapper-id') || `mermaid-wrapper-${i}-${Math.random().toString(36).substr(2, 9)}`;
- pre.setAttribute('data-mermaid-wrapper-id', wrapperId);
+ Array.from(mermaidNodes).forEach(async (codeNode, index) => {
+ const preNode = codeNode.parentElement;
+ if (!preNode || preNode.tagName !== 'PRE') return;
- let wrapper = container.querySelector(`#${wrapperId}`) as HTMLDivElement | null;
- if (!wrapper) {
- wrapper = document.createElement('div');
- wrapper.id = wrapperId;
- wrapper.className = 'mermaid-diagram-wrapper w-full border border-border bg-slate-950/20 dark:bg-slate-950/40 p-6 overflow-x-auto flex flex-col justify-center items-center my-6 rounded-none transition-colors';
- pre.parentNode?.insertBefore(wrapper, pre.nextSibling);
+ // Extract original code. We save it in a data attribute to allow re-rendering on theme change.
+ if (!preNode.dataset.mermaidCode) {
+ preNode.dataset.mermaidCode = codeNode.textContent || '';
+ }
+ const code = preNode.dataset.mermaidCode;
+ if (!code) return;
+
+ const id = `mermaid-svg-${index}-${Math.random().toString(36).substring(2, 9)}`;
+
+ try {
+ const { svg } = await mermaid.render(id, code);
+ if (!isActive) return;
+
+ // Check if we already injected an SVG wrapper next to this PRE
+ let svgWrapper = preNode.nextElementSibling as HTMLElement;
+ if (!svgWrapper || !svgWrapper.classList.contains('mermaid-wrapper')) {
+ svgWrapper = document.createElement('div');
+ svgWrapper.className = 'mermaid-wrapper flex justify-center my-8 p-4 bg-zinc-50 dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800';
+ // zero rounding rule
+ svgWrapper.style.borderRadius = '0px';
+ preNode.parentNode?.insertBefore(svgWrapper, preNode.nextSibling);
}
- injectedDivs.push(wrapper);
-
- pre.style.display = 'none';
-
- const diagramId = `mermaid-svg-${i}-${Math.random().toString(36).substr(2, 9)}`;
- try {
- wrapper.innerHTML = 'Compilando diagrama...';
-
- const cleanedCode = rawCode
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/&/g, '&')
- .trim();
-
- const { svg } = await mermaid.render(diagramId, cleanedCode);
- if (active) {
- wrapper.innerHTML = svg;
- const svgEl = wrapper.querySelector('svg');
- if (svgEl) {
- svgEl.style.maxWidth = '100%';
- svgEl.style.height = 'auto';
- svgEl.querySelectorAll('rect, polygon, path').forEach((shape) => {
- shape.setAttribute('rx', '0');
- shape.setAttribute('ry', '0');
- });
- }
- }
- } catch (err) {
- console.error('[Mermaid compile error]', err);
- if (active) {
- wrapper.innerHTML = `
-
-
Erro de renderização do diagrama
-
${err instanceof Error ? err.message : String(err)}
-
- `;
- pre.style.display = 'block';
- }
- }
+ svgWrapper.innerHTML = svg;
+
+ // Hide the original code block
+ preNode.style.display = 'none';
+ } catch (err) {
+ console.error('Failed to render mermaid diagram', err);
}
- } catch (err) {
- console.error('Failed to run mermaid rendering:', err);
- }
- };
+ });
+ }
renderDiagrams();
return () => {
- active = false;
- injectedDivs.forEach((div) => {
- div.remove();
- });
- const preElements = container.querySelectorAll('pre');
- preElements.forEach((pre) => {
- if (pre.getAttribute('data-mermaid-code')) {
- pre.removeAttribute('data-mermaid-wrapper-id');
- pre.removeAttribute('data-mermaid-code');
- pre.style.display = '';
- }
- });
+ isActive = false;
};
- }, [html, resolvedTheme, containerRef]);
+ }, [containerRef, containerId, resolvedTheme]);
return null;
}
diff --git a/lib/auth.ts b/lib/auth.ts
index e5d229c..c690a0e 100644
--- a/lib/auth.ts
+++ b/lib/auth.ts
@@ -4,6 +4,7 @@ import { nextCookies } from 'better-auth/next-js';
import { db } from '@/lib/db';
import { authSchema } from '@/lib/db/schema';
+import { sendWelcomeEmail } from '@/lib/email';
const baseURL =
process.env.BETTER_AUTH_URL?.replace(/\/$/, '') ||
@@ -20,6 +21,19 @@ export const auth = betterAuth({
provider: 'pg',
schema: authSchema,
}),
+ databaseHooks: {
+ user: {
+ create: {
+ after: async (user) => {
+ try {
+ await sendWelcomeEmail(user.email, user.name);
+ } catch (err) {
+ console.error('[auth databaseHooks user.create.after] Welcome email failed:', err);
+ }
+ },
+ },
+ },
+ },
emailAndPassword: { enabled: true },
socialProviders: {
...(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET
diff --git a/lib/content/schemas.ts b/lib/content/schemas.ts
index 55d72a5..d0f7135 100644
--- a/lib/content/schemas.ts
+++ b/lib/content/schemas.ts
@@ -225,7 +225,7 @@ export interface InterviewEnglishTopic {
}
/** Guias de engenharia aplicada ao dia-a-dia (produto, APIs, operação). */
-export const ENGINEERING_WORK_PILLARS = ['frontend', 'backend', 'devops', 'softskills', 'ia'] as const;
+export const ENGINEERING_WORK_PILLARS = ['frontend', 'backend', 'devops', 'softskills', 'ia', 'web3'] as const;
export const EngineeringWorkPillar = z.enum(ENGINEERING_WORK_PILLARS);
export type EngineeringWorkPillar = z.infer;
diff --git a/lib/courses/certificate.ts b/lib/courses/certificate.ts
index 2d7554b..c6008b1 100644
--- a/lib/courses/certificate.ts
+++ b/lib/courses/certificate.ts
@@ -44,7 +44,7 @@ export async function buildCertificateMetadata(
ctx.moduleHydrated.certificateTitle,
ctx.pack.title,
"certificado curso",
- "Algoria",
+ "Acite",
],
openGraphType: "article",
});
diff --git a/lib/email.ts b/lib/email.ts
new file mode 100644
index 0000000..e75be62
--- /dev/null
+++ b/lib/email.ts
@@ -0,0 +1,17 @@
+import { sendEmail } from './email/config';
+import { getWelcomeEmailTemplate } from './email/templates/welcome';
+
+/**
+ * Sends a welcome email to a newly registered user.
+ * Imports layout templates and routes parameters to the Resend sending client.
+ */
+export async function sendWelcomeEmail(toEmail: string, name?: string | null): Promise {
+ const greetingName = name ? name.trim() : 'dev';
+ const { subject, html } = getWelcomeEmailTemplate({ name: greetingName });
+
+ await sendEmail({
+ to: toEmail,
+ subject,
+ html,
+ });
+}
diff --git a/lib/email/config.ts b/lib/email/config.ts
new file mode 100644
index 0000000..237697f
--- /dev/null
+++ b/lib/email/config.ts
@@ -0,0 +1,70 @@
+import { Resend } from 'resend';
+
+const resendApiKey = process.env.RESEND_API_KEY;
+export const resend = resendApiKey ? new Resend(resendApiKey) : null;
+
+export const FROM_EMAIL = process.env.RESEND_FROM_EMAIL || 'Acite ';
+
+export interface SendEmailOptions {
+ to: string;
+ subject: string;
+ html: string;
+}
+
+/**
+ * Low-level email sending function.
+ * Uses Resend if RESEND_API_KEY is set. In development, if Resend fails (e.g. sandbox domain restriction),
+ * it gracefully prints a warning and falls back to logging the email to the console.
+ */
+export async function sendEmail({ to, subject, html }: SendEmailOptions): Promise {
+ const isDev = process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_ENVIRONMENT === 'development';
+
+ if (resend) {
+ try {
+ const response = await resend.emails.send({
+ from: FROM_EMAIL,
+ to,
+ subject,
+ html,
+ });
+
+ if (response.error) {
+ if (isDev) {
+ console.warn(`\n⚠️ [Resend Sandbox/API Warning]: Falha no envio real para ${to} (Resend: ${response.error.message}).`);
+ console.warn(`Exibindo cópia do e-mail no console devido ao ambiente de desenvolvimento:`);
+ logEmailMock(to, subject, html);
+ return;
+ }
+
+ console.error('[Resend Error sending email]:', response.error);
+ throw new Error(response.error.message);
+ } else {
+ console.log(`[Resend Success]: Email sent to ${to} (ID: ${response.data?.id})`);
+ }
+ } catch (err) {
+ if (isDev) {
+ const errMsg = err instanceof Error ? err.message : String(err);
+ console.warn(`\n⚠️ [Resend Sandbox/API Exception]: Falha no envio real para ${to} (Erro: ${errMsg}).`);
+ console.warn(`Exibindo cópia do e-mail no console devido ao ambiente de desenvolvimento:`);
+ logEmailMock(to, subject, html);
+ return;
+ }
+
+ console.error('[Resend Exception sending email]:', err);
+ throw err;
+ }
+ } else {
+ logEmailMock(to, subject, html);
+ }
+}
+
+function logEmailMock(to: string, subject: string, html: string) {
+ console.log('\n========================================================================');
+ console.log('📬 [EMAIL MOCK LOG]');
+ console.log(`Para: ${to}`);
+ console.log(`Assunto: ${subject}`);
+ console.log(`De: ${FROM_EMAIL}`);
+ console.log('Corpo HTML:');
+ console.log(html);
+ console.log('========================================================================\n');
+}
diff --git a/lib/email/templates/base.ts b/lib/email/templates/base.ts
new file mode 100644
index 0000000..d6e3eab
--- /dev/null
+++ b/lib/email/templates/base.ts
@@ -0,0 +1,50 @@
+export interface BaseEmailLayoutProps {
+ title: string;
+ previewText?: string;
+ contentHtml: string;
+}
+
+/**
+ * Wraps dynamic body content in the standard dark-mode Algoria email HTML shell.
+ * Adheres strictly to the brand aesthetics (dark deep-slate backgrounds, sharp rounded-none edges).
+ */
+export function getBaseEmailLayout({ title, previewText, contentHtml }: BaseEmailLayoutProps): string {
+ const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
+ const previewTextHtml = previewText
+ ? `${previewText}`
+ : '';
+
+ return `
+
+
+
+
+ ${title}
+
+
+ ${previewTextHtml}
+
+
+
+
+
+ Aprenda lendo código
+ |
+
+
+
+ |
+ ${contentHtml}
+ |
+
+
+
+ |
+ Acite — Domine algoritmos de verdade
+ Você recebeu este e-mail porque criou uma conta no Acite. Se você não fez essa solicitação, por favor ignore este e-mail.
+ |
+
+
+
+`;
+}
diff --git a/lib/email/templates/welcome.ts b/lib/email/templates/welcome.ts
new file mode 100644
index 0000000..347a6ea
--- /dev/null
+++ b/lib/email/templates/welcome.ts
@@ -0,0 +1,136 @@
+import { getBaseEmailLayout } from './base';
+
+export interface WelcomeEmailData {
+ name: string;
+}
+
+/**
+ * Generates a highly engaging and comprehensive welcome onboarding email.
+ * Outlines the main platform features and sets clear next steps for the user.
+ */
+export function getWelcomeEmailTemplate({ name }: WelcomeEmailData): { subject: string; html: string } {
+ const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
+ const subject = 'Boas-vindas ao Acite! Sua jornada dev começa aqui 🚀';
+
+ const contentHtml = `
+
+
+ Olá, ${name}! Seu acesso ao Acite está liberado.
+
+
+ Ficamos muito empolgados em ter você aqui. A maioria das pessoas tenta aprender algoritmos e estruturas de dados decorando fórmulas e batendo a cabeça no teclado escrevendo código do zero sem entender o básico.
+
+
+ No Acite, nós fazemos o oposto. Acreditamos que a melhor forma de se tornar um programador de elite é lendo e analisando código de alta qualidade, linha por linha.
+
+
+
+
+
+
+
+
+ O que você vai encontrar na plataforma?
+
+
+
+
+
+ | 🧠 |
+
+
+ O Code Player Interativo
+
+
+ Nosso visualizador de código funciona como um reprodutor de vídeo. Dê play e veja o ponteiro de execução passar linha por linha, com comentários dinâmicos em 3 níveis de profundidade (Fácil, Médio e Avançado).
+
+ |
+
+
+
+
+
+
+ | ⚔️ |
+
+
+ Brute-Force vs. Solução Ótima
+
+
+ Compare implementações ineficientes diretamente contra os códigos de alta performance. Entenda no visual a real diferença teórica e prática na otimização de CPU e Memória (Big O).
+
+ |
+
+
+
+
+
+
+ | ⚡ |
+
+
+ Guias de Engenharia Aplicada
+
+
+ Esqueça problemas abstratos que nunca acontecem na prática. Nos nossos guias, conectamos estruturas de dados com a realidade: sistemas de cache, pipelines RAG para IA, arquitetura de multi-agentes e segurança em produção.
+
+ |
+
+
+
+
+
+
+ | 🗣️ |
+
+
+ Trilha de Inglês Técnico (Interview English)
+
+
+ Prepare-se para vagas internacionais. Aprenda o vocabulário técnico preciso para dinâmicas de System Design, live coding e comunicação profissional em reuniões de engenharia.
+
+ |
+
+
+
+
+
+
+ | 🔥 |
+
+
+ Desafio Diário (Daily Challenge)
+
+
+ Construa consistência sem esforço. Precisa de apenas 3 minutos diários na página de código ativa para manter seu streak e fogo de estudos ativo na plataforma.
+
+ |
+
+
+
+
+
+
+
Sua primeira missão:
+
+ Acesse a seção de Problemas, selecione o desafio clássico "Two Sum" e dê play na solução ótima para ver como o player ajuda a entender o funcionamento interno de hash maps.
+
+
+ `;
+
+ const html = getBaseEmailLayout({
+ title: subject,
+ previewText: 'Domine algoritmos lendo código de verdade com o Code Player.',
+ contentHtml,
+ });
+
+ return { subject, html };
+}
diff --git a/lib/seo/build-metadata.ts b/lib/seo/build-metadata.ts
index ca514a8..9333bde 100644
--- a/lib/seo/build-metadata.ts
+++ b/lib/seo/build-metadata.ts
@@ -3,7 +3,7 @@ import type { Metadata } from 'next';
import { getSiteOrigin } from './site';
export type BuildPublicMetadataInput = {
- /** Com template do layout: `%s · Algoria` */
+ /** Com template do layout: `%s · Acite` */
title?: string;
/** Sem sufixo automático (ex.: página inicial) */
titleAbsolute?: string;
@@ -18,7 +18,7 @@ export type BuildPublicMetadataInput = {
/**
* Metadados consistentes: canonical, Open Graph, Twitter, robots.
- * O layout define `title.template` como `%s · Algoria` (exceto quando `titleAbsolute`).
+ * O layout define `title.template` como `%s · Acite` (exceto quando `titleAbsolute`).
*/
export function buildPublicMetadata(opts: BuildPublicMetadataInput): Metadata {
const origin = getSiteOrigin();
@@ -31,13 +31,13 @@ export function buildPublicMetadata(opts: BuildPublicMetadataInput): Metadata {
const uniqueKw = kw ? [...new Set(kw.map((k) => k.trim()).filter(Boolean))].slice(0, 24) : undefined;
const titleMeta: Metadata['title'] =
- opts.titleAbsolute !== undefined ? { absolute: opts.titleAbsolute } : (opts.title ?? 'Algoria');
+ opts.titleAbsolute !== undefined ? { absolute: opts.titleAbsolute } : (opts.title ?? 'Acite');
const ogTitle =
opts.titleAbsolute ??
- (typeof opts.title === 'string' ? opts.title : 'Algoria');
+ (typeof opts.title === 'string' ? opts.title : 'Acite');
- const defaultImage = `${origin}/algoria-logo.png`;
+ const defaultImage = `${origin}/ae-complete-logo.png`;
const shareImage = opts.image ? (opts.image.startsWith('http') ? opts.image : `${origin}${opts.image.startsWith('/') ? '' : '/'}${opts.image}`) : defaultImage;
const isSquare = opts.imageIsSquare || !opts.image;
@@ -60,7 +60,7 @@ export function buildPublicMetadata(opts: BuildPublicMetadataInput): Metadata {
title: ogTitle,
description,
url: canonical,
- siteName: 'Algoria',
+ siteName: 'Acite',
locale: opts.openGraphLocale ?? 'pt_BR',
type: opts.openGraphType ?? 'website',
images: [
diff --git a/lib/seo/site.ts b/lib/seo/site.ts
index c8816a0..598b8e2 100644
--- a/lib/seo/site.ts
+++ b/lib/seo/site.ts
@@ -1,6 +1,6 @@
/**
* Origem canónica do site para SEO (sem barra final).
- * Preferir `NEXT_PUBLIC_APP_URL` (ex.: https://algoria.app ou http://localhost:3000).
+ * Preferir `NEXT_PUBLIC_APP_URL` (ex.: https://acite.app ou http://localhost:3000).
* Fallback: https://`NEXT_PUBLIC_APP_DOMAIN`
*/
export function getSiteOrigin(): string {
@@ -13,7 +13,7 @@ export function getSiteOrigin(): string {
/* continua */
}
}
- let domain = process.env.NEXT_PUBLIC_APP_DOMAIN?.trim() || 'algoria.app';
+ let domain = process.env.NEXT_PUBLIC_APP_DOMAIN?.trim() || 'acite.app';
domain = domain.replace(/^https?:\/\//, '').replace(/\/$/, '');
return `https://${domain}`;
}
diff --git a/lib/seo/structured-data.ts b/lib/seo/structured-data.ts
index 301a978..1e021b6 100644
--- a/lib/seo/structured-data.ts
+++ b/lib/seo/structured-data.ts
@@ -43,7 +43,7 @@ export function articleJsonLd(input: {
description: truncateMetaDescription(input.description),
url: absoluteUrl(input.pathname),
inLanguage: input.inLanguage ?? 'pt-BR',
- author: { '@type': 'Organization', name: 'Algoria' },
+ author: { '@type': 'Organization', name: 'Acite' },
publisher: { '@id': `${origin}/#organization` },
};
}
diff --git a/package.json b/package.json
index 0aa4c45..3f721e5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,11 @@
{
- "name": "algoria",
- "version": "0.1.0",
+ "name": "acite",
+ "version": "2.0.0",
+ "author": {
+ "name": "Jonatas Silva - Founder",
+ "email": "jonatasilva118@gmail.com"
+ },
+ "license": "MIT",
"private": true,
"scripts": {
"dev": "next dev",
@@ -36,6 +41,7 @@
"posthog-js": "^1.372.6",
"react": "19.2.4",
"react-dom": "19.2.4",
+ "resend": "^6.12.4",
"shiki": "^4.0.2",
"stripe": "^22.1.0",
"tailwind-merge": "^3.5.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 63f7232..e95d341 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -74,6 +74,9 @@ importers:
react-dom:
specifier: 19.2.4
version: 19.2.4(react@19.2.4)
+ resend:
+ specifier: ^6.12.4
+ version: 6.12.4
shiki:
specifier: ^4.0.2
version: 4.0.2
@@ -1606,6 +1609,9 @@ packages:
'@shikijs/vscode-textmate@10.0.2':
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
+ '@stablelib/base64@1.0.1':
+ resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==}
+
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
@@ -2326,8 +2332,8 @@ packages:
peerDependencies:
cytoscape: ^3.2.0
- cytoscape@3.33.4:
- resolution: {integrity: sha512-HIN5Pmd9MrX9BkV7tDwnOcEJCSFvCpc8X97h3f508J6I5FsqAY65wKOCvgH2CuP42CaahWaz4tuh32SOOIH7ww==}
+ cytoscape@3.34.0:
+ resolution: {integrity: sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==}
engines: {node: '>=0.10'}
d3-array@2.12.1:
@@ -2870,6 +2876,9 @@ packages:
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ fast-sha256@1.3.0:
+ resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==}
+
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
@@ -3659,6 +3668,9 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
+ postal-mime@2.7.4:
+ resolution: {integrity: sha512-0WdnFQYUrPGGTFu1uOqD2s7omwua8xaeYGdO6rb88oD5yJ/4pPHDA4sdWqfD8wQVfCny563n/HQS7zTFft+f/g==}
+
postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
@@ -3780,6 +3792,15 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
+ resend@6.12.4:
+ resolution: {integrity: sha512-lRpJ2Hxd+ht+JPDm97juRcUp9HOMuZyxaRFRFmc9Tx8iNWiei94Dx9v6SWufgKk2667C/uCeKKspMotOHSpCSg==}
+ engines: {node: '>=20'}
+ peerDependencies:
+ '@react-email/render': '*'
+ peerDependenciesMeta:
+ '@react-email/render':
+ optional: true
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -3921,6 +3942,9 @@ packages:
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ standardwebhooks@1.0.0:
+ resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==}
+
state-local@1.0.7:
resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
@@ -5491,6 +5515,8 @@ snapshots:
'@shikijs/vscode-textmate@10.0.2': {}
+ '@stablelib/base64@1.0.1': {}
+
'@standard-schema/spec@1.1.0': {}
'@swc/helpers@0.5.15':
@@ -6199,17 +6225,17 @@ snapshots:
csstype@3.2.3: {}
- cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.4):
+ cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0):
dependencies:
cose-base: 1.0.3
- cytoscape: 3.33.4
+ cytoscape: 3.34.0
- cytoscape-fcose@2.2.0(cytoscape@3.33.4):
+ cytoscape-fcose@2.2.0(cytoscape@3.34.0):
dependencies:
cose-base: 2.2.0
- cytoscape: 3.33.4
+ cytoscape: 3.34.0
- cytoscape@3.33.4: {}
+ cytoscape@3.34.0: {}
d3-array@2.12.1:
dependencies:
@@ -6912,6 +6938,8 @@ snapshots:
fast-levenshtein@2.0.6: {}
+ fast-sha256@1.3.0: {}
+
fastq@1.20.1:
dependencies:
reusify: 1.1.0
@@ -7439,9 +7467,9 @@ snapshots:
'@mermaid-js/parser': 1.1.1
'@types/d3': 7.4.3
'@upsetjs/venn.js': 2.0.0
- cytoscape: 3.33.4
- cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.4)
- cytoscape-fcose: 2.2.0(cytoscape@3.33.4)
+ cytoscape: 3.34.0
+ cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.0)
+ cytoscape-fcose: 2.2.0(cytoscape@3.34.0)
d3: 7.9.0
d3-sankey: 0.12.3
dagre-d3-es: 7.0.14
@@ -7704,6 +7732,8 @@ snapshots:
possible-typed-array-names@1.1.0: {}
+ postal-mime@2.7.4: {}
+
postcss-selector-parser@6.0.10:
dependencies:
cssesc: 3.0.0
@@ -7848,6 +7878,11 @@ snapshots:
require-from-string@2.0.2: {}
+ resend@6.12.4:
+ dependencies:
+ postal-mime: 2.7.4
+ standardwebhooks: 1.0.0
+
resolve-from@4.0.0: {}
resolve-pkg-maps@1.0.0: {}
@@ -8052,6 +8087,11 @@ snapshots:
stackback@0.0.2: {}
+ standardwebhooks@1.0.0:
+ dependencies:
+ '@stablelib/base64': 1.0.1
+ fast-sha256: 1.3.0
+
state-local@1.0.7: {}
std-env@4.1.0: {}
diff --git a/public/ae-complete-logo-light.png b/public/ae-complete-logo-light.png
new file mode 100644
index 0000000..82ed7b9
Binary files /dev/null and b/public/ae-complete-logo-light.png differ
diff --git a/public/ae-complete-logo.png b/public/ae-complete-logo.png
new file mode 100644
index 0000000..7a187d2
Binary files /dev/null and b/public/ae-complete-logo.png differ
diff --git a/public/ae-logo-quadrado.png b/public/ae-logo-quadrado.png
new file mode 100644
index 0000000..b725b3b
Binary files /dev/null and b/public/ae-logo-quadrado.png differ
diff --git a/public/algoria-logo.png b/public/algoria-logo.png
index 6f2eaa9..a07eea4 100644
Binary files a/public/algoria-logo.png and b/public/algoria-logo.png differ
diff --git a/public/creator-support/README.md b/public/creator-support/README.md
index 2e5c671..0304865 100644
--- a/public/creator-support/README.md
+++ b/public/creator-support/README.md
@@ -1,6 +1,6 @@
-# 📦 Kit do Criador de Conteúdo — Algoria
+# 📦 Kit do Criador de Conteúdo — Acite
-Bem-vindo ao material de apoio para criação de conteúdo na plataforma Algoria.
+Bem-vindo ao material de apoio para criação de conteúdo na plataforma Acite.
Este kit contém tudo que você precisa para criar e importar artigos pelo painel admin.
---
diff --git a/public/creator-support/compilar-json.js b/public/creator-support/compilar-json.js
index 724f816..ef3eef1 100644
--- a/public/creator-support/compilar-json.js
+++ b/public/creator-support/compilar-json.js
@@ -1,6 +1,6 @@
/* eslint-disable */
/**
- * Script de Criação do JSON para Importação na Algoria
+ * Script de Criação do JSON para Importação na Acite
*
* Como usar:
* 1. Edite as configurações abaixo (CONFIGURAÇÃO DO CONTEÚDO).
@@ -46,8 +46,8 @@ const CONFIG = {
estimatedMinutes: 5,
// Pilar do conteúdo (OBRIGATÓRIO apenas para type "engineering-work"):
- // Opções: 'frontend' | 'backend' | 'devops' | 'softskills' | 'ia'
- pillar: 'frontend',
+ // Opções: 'frontend' | 'backend' | 'devops' | 'softskills' | 'ia' | 'web3'
+ pillar: 'web3',
// Caminho da imagem de destaque (opcional)
image: '/default-cover.png'
@@ -64,7 +64,7 @@ function compilar() {
const mdPath = path.join(__dirname, markdownFileName);
const outputPath = path.join(__dirname, outputFileName);
- console.log('--- Compilador de Conteúdo Algoria ---');
+ console.log('--- Compilador de Conteúdo Acite ---');
// Verifica se o arquivo markdown existe
if (!fs.existsSync(mdPath)) {
@@ -118,7 +118,7 @@ function compilar() {
console.log(`${outputPath}\n`);
console.log('Agora você pode:');
console.log('1. Abrir esse arquivo e copiar o conteúdo JSON.');
- console.log('2. Acessar o Painel Administrativo da Algoria (/admin/content).');
+ console.log('2. Acessar o Painel Administrativo da Acite (/admin/content).');
console.log('3. Clicar em "Importar" e colar ou fazer o upload do arquivo para salvar na plataforma!');
console.log('\n----------------------------------------\n');
diff --git a/public/creator-support/exemplo-conteudo.md b/public/creator-support/exemplo-conteudo.md
index 0770b69..f94df41 100644
--- a/public/creator-support/exemplo-conteudo.md
+++ b/public/creator-support/exemplo-conteudo.md
@@ -1,6 +1,6 @@
-# Guia de Referência de Formatação — Algoria Creator Kit
+# Guia de Referência de Formatação — Acite Creator Kit
-Este é o **arquivo de referência completo** de todos os recursos de formatação disponíveis para criadores de conteúdo na plataforma Algoria.
+Este é o **arquivo de referência completo** de todos os recursos de formatação disponíveis para criadores de conteúdo na plataforma Acite.
Use-o como modelo ou consulta rápida ao escrever seus artigos.
---
@@ -24,7 +24,7 @@ Você pode usar toda a formatação padrão do CommonMark/GitHub Flavored Markdo
- *Itálico* → `*texto*`
- ~~Tachado~~ → `~~texto~~`
- `Código em linha` → `` `código` ``
-- [Link externo](https://algoria.dev) → `[texto](url)`
+- [Link externo](https://acite.dev) → `[texto](url)`
- > Citação em bloco → `> texto`
### 1.2 Listas
@@ -83,7 +83,7 @@ Use alertas para enfatizar informações específicas. Não use mais de um alert
## 3. Componentes Didáticos Customizados
-A plataforma Algoria suporta componentes interativos embutidos no Markdown usando a sintaxe `:::tipo { ... } :::`.
+A plataforma Acite suporta componentes interativos embutidos no Markdown usando a sintaxe `:::tipo { ... } :::`.
### 3.1 Figuras com Legenda (`:::didactic-figure`)
diff --git a/public/engenharia/blockchain_intro.png b/public/engenharia/blockchain_intro.png
new file mode 100644
index 0000000..e603269
Binary files /dev/null and b/public/engenharia/blockchain_intro.png differ
diff --git a/public/engenharia/ethereum_evm.png b/public/engenharia/ethereum_evm.png
new file mode 100644
index 0000000..3afdb1d
Binary files /dev/null and b/public/engenharia/ethereum_evm.png differ
diff --git a/public/engenharia/web3_future.png b/public/engenharia/web3_future.png
new file mode 100644
index 0000000..1f84599
Binary files /dev/null and b/public/engenharia/web3_future.png differ
diff --git a/public/engenharia/web3_security.png b/public/engenharia/web3_security.png
new file mode 100644
index 0000000..296c4d1
Binary files /dev/null and b/public/engenharia/web3_security.png differ
diff --git a/public/preview.webp b/public/preview.webp
index 37edb88..7fe8ec8 100644
Binary files a/public/preview.webp and b/public/preview.webp differ