fix: eslint and build

This commit is contained in:
2026-02-07 09:36:17 +01:00
parent 1135b33792
commit 35b7ba56ed
14 changed files with 3376 additions and 490 deletions

View File

@@ -2,8 +2,9 @@ import React from 'react';
import { technologies } from './data';
import TechnologyContent from './content';
export default function TechnologyPage({ params }: { params: { slug: string } }) {
return <TechnologyContent slug={params.slug} />;
export default async function TechnologyPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
return <TechnologyContent slug={slug} />;
}
// Generate static params for these dynamic routes

View File

@@ -1,7 +1,7 @@
import mintelConfig from "@mintel/eslint-config/next";
import { nextConfig } from "@mintel/eslint-config/next";
export default [
...mintelConfig,
...nextConfig,
{
rules: {
"no-console": "warn",

View File

@@ -1,7 +1,30 @@
import withMintelConfig from "@mintel/next-config";
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
output: 'standalone',
async rewrites() {
const umamiUrl =
process.env.UMAMI_API_ENDPOINT ||
process.env.UMAMI_SCRIPT_URL ||
process.env.NEXT_PUBLIC_UMAMI_SCRIPT_URL ||
"https://analytics.infra.mintel.me";
const glitchtipUrl = process.env.SENTRY_DSN
? new URL(process.env.SENTRY_DSN).origin
: "https://errors.infra.mintel.me";
return [
{
source: "/stats/:path*",
destination: `${umamiUrl}/:path*`,
},
{
source: "/errors/:path*",
destination: `${glitchtipUrl}/:path*`,
},
];
},
};
export default nextConfig;
export default withMintelConfig(nextConfig);

View File

@@ -7,7 +7,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint": "eslint .",
"test": "npm run test:links",
"test:links": "tsx ./scripts/test-links.ts",
"test:file-examples": "tsx ./scripts/test-file-examples-comprehensive.ts",
@@ -20,11 +20,19 @@
"video:render:contact": "remotion render video/index.ts ContactFormShowcase out/contact-showcase.mp4 --concurrency=1 --codec=h264 --crf=16 --pixel-format=yuv420p --overwrite",
"video:render:button": "remotion render video/index.ts ButtonShowcase out/button-showcase.mp4 --concurrency=1 --codec=h264 --crf=16 --pixel-format=yuv420p --overwrite",
"video:render:all": "npm run video:render:contact && npm run video:render:button",
"pagespeed:test": "tsx ./scripts/pagespeed-sitemap.ts",
"pagespeed:test": "mintel pagespeed test",
"cms:bootstrap": "DIRECTUS_URL=http://localhost:8055 npx tsx --env-file=.env scripts/setup-directus.ts",
"cms:push:staging": "../../scripts/sync-directus.sh push staging",
"cms:pull:staging": "../../scripts/sync-directus.sh pull staging",
"cms:push:testing": "../../scripts/sync-directus.sh push testing",
"cms:pull:testing": "../../scripts/sync-directus.sh pull testing",
"cms:push:prod": "../../scripts/sync-directus.sh push production",
"cms:pull:prod": "../../scripts/sync-directus.sh pull production",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@mintel/next-utils": "^1.0.1",
"@mintel/next-utils": "^1.1.13",
"@sentry/nextjs": "^10.38.0",
"@react-pdf/renderer": "^4.3.2",
"@remotion/bundler": "^4.0.414",
"@remotion/cli": "^4.0.414",
@@ -60,8 +68,9 @@
"zod": "3.22.3"
},
"devDependencies": {
"@mintel/eslint-config": "^1.0.1",
"@mintel/tsconfig": "^1.0.1",
"@mintel/cli": "^1.1.13",
"@mintel/eslint-config": "^1.1.13",
"@mintel/tsconfig": "^1.1.13",
"@tailwindcss/typography": "^0.5.15",
"@types/node": "^25.0.6",
"@types/prismjs": "^1.26.5",

View File

@@ -0,0 +1,73 @@
import {
createMintelDirectusClient,
ensureDirectusAuthenticated,
} from "@mintel/next-utils";
import { updateSettings } from "@directus/sdk";
const client = createMintelDirectusClient();
async function setupBranding() {
const prjName = process.env.PROJECT_NAME || "Mintel.me";
const prjColor = process.env.PROJECT_COLOR || "#ff00ff";
console.log(`🎨 Refining Directus Branding for ${prjName}...`);
await ensureDirectusAuthenticated(client);
const cssInjection = `
<style>
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap');
body, .v-app { font-family: 'Outfit', sans-serif !important; }
.public-view .v-card {
backdrop-filter: blur(20px);
background: rgba(255, 255, 255, 0.9) !important;
border-radius: 32px !important;
box-shadow: 0 50px 100px -20px rgba(0, 0, 0, 0.4) !important;
border: 1px solid rgba(255, 255, 255, 0.3) !important;
}
.v-navigation-drawer { background: #000c24 !important; }
.v-list-item--active {
color: ${prjColor} !important;
background: rgba(255, 0, 255, 0.1) !important;
}
</style>
<div style="font-family: 'Outfit', sans-serif; text-align: center; margin-top: 24px;">
<p style="color: rgba(255,255,255,0.6); font-size: 11px; letter-spacing: 2px; margin-bottom: 4px; font-weight: 600; text-transform: uppercase;">Mintel Infrastructure Engine</p>
<h1 style="color: #ffffff; font-size: 20px; font-weight: 700; margin: 0; letter-spacing: -0.5px;">${prjName.toUpperCase()} <span style="color: ${prjColor};">SYNC.</span></h1>
</div>
`;
try {
await client.request(
updateSettings({
project_name: prjName,
project_color: prjColor,
public_note: cssInjection,
module_bar_background: "#00081a",
theme_light_overrides: {
primary: prjColor,
borderRadius: "12px",
navigationBackground: "#000c24",
navigationForeground: "#ffffff",
moduleBarBackground: "#00081a",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any),
);
console.log("✨ Branding applied!");
} catch (error) {
console.error("❌ Error during bootstrap:", error);
}
}
setupBranding()
.then(() => {
process.exit(0);
})
.catch((err) => {
console.error("🚨 Fatal bootstrap error:", err);
process.exit(1);
});

View File

@@ -8,15 +8,11 @@ import { ConceptPrice, ConceptAutomation } from '../../Landing/ConceptIllustrati
import { Info, Download, Share2, RefreshCw } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import dynamic from 'next/dynamic';
import { EstimationPDF } from '../../EstimationPDF';
// EstimationPDF will be imported dynamically where used or inside the and client-side block
import IconWhite from '../../../assets/logo/Icon White Transparent.png';
import LogoBlack from '../../../assets/logo/Logo Black Transparent.png';
// Dynamically import PDF components to avoid SSR issues
const PDFDownloadLink = dynamic(
() => import('@react-pdf/renderer').then((mod) => mod.PDFDownloadLink),
{ ssr: false }
);
// PDF components removed from top-level dynamic import to fix ESM resolution issues in Next.js 16/Webpack
interface PriceCalculationProps {
state: FormState;
@@ -44,8 +40,7 @@ export function PriceCalculation({
setPdfLoading(true);
try {
const { pdf } = await import('@react-pdf/renderer');
const { EstimationPDF } = await import('../../EstimationPDF');
const doc = <EstimationPDF
state={state}
totalPrice={totalPrice}
@@ -56,6 +51,8 @@ export function PriceCalculation({
footerLogo={typeof LogoBlack === 'string' ? LogoBlack : (LogoBlack as any).src}
/>;
const { pdf } = await import('@react-pdf/renderer');
// Minimum loading time of 2 seconds for better UX
const [blob] = await Promise.all([
pdf(doc).toBlob(),