diff --git a/.dev.vars.example b/.dev.vars.example new file mode 100644 index 0000000..77ec167 --- /dev/null +++ b/.dev.vars.example @@ -0,0 +1,18 @@ +# Cloudflare Pages Function secrets for /api/contact +# Local default (smtp4dev) +SMTP_HOST=127.0.0.1 +SMTP_PORT=2525 +SMTP_SECURE=false +SMTP_USER= +SMTP_PASS= +MAIL_FROM_EMAIL=noreply@ultraviolet.rs +TEAM_CONTACT_EMAIL=info@ultraviolet.rs + +# Production example (Google SMTP / Gmail Workspace) +# SMTP_HOST=smtp.gmail.com +# SMTP_PORT=465 +# SMTP_SECURE=true +# SMTP_USER=your-production-email@yourdomain.com +# SMTP_PASS=your-google-app-password +# MAIL_FROM_EMAIL=your-production-email@yourdomain.com +# TEAM_CONTACT_EMAIL=info@ultraviolet.rs diff --git a/.gitignore b/.gitignore index 16d54bb..a68bfb1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,13 @@ pnpm-debug.log* # jetbrains setting folder .idea/ + +*.test +node_modules +.astro +dist +.env* +# wrangler files +.wrangler +.dev.vars* +!.dev.vars.example diff --git a/astro.config.mjs b/astro.config.mjs index 12a8fac..6cd4982 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -24,4 +24,10 @@ export default defineConfig({ ], adapter: cloudflare(), + + vite: { + ssr: { + external: ['nodemailer'], + }, + }, }); diff --git a/package.json b/package.json index f483cf8..0fa0c7a 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,9 @@ "@astrojs/cloudflare": "^12", "@astrojs/sitemap": "^3.7.2", "@astrojs/tailwind": "^6.0.2", - "astro": "^5.17.1" + "astro": "^5.17.1", + "node": "^25.6.1", + "nodemailer": "^8.0.4" }, "devDependencies": { "@astrojs/check": "^0.9.6", @@ -29,6 +31,7 @@ "@eslint/json": "^1.1.0", "@eslint/markdown": "^7.5.1", "@tailwindcss/typography": "^0.5.19", + "@types/nodemailer": "^7.0.11", "@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/parser": "^8.28.0", "eslint": "^9.39.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a542ea8..cb7fa67 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,12 @@ importers: astro: specifier: ^5.17.1 version: 5.17.2(@types/node@24.12.0)(jiti@2.6.1)(rollup@4.57.1)(typescript@5.9.3)(yaml@2.8.2) + node: + specifier: ^25.6.1 + version: 25.8.2 + nodemailer: + specifier: ^8.0.4 + version: 8.0.4 devDependencies: '@astrojs/check': specifier: ^0.9.6 @@ -39,6 +45,9 @@ importers: '@tailwindcss/typography': specifier: ^0.5.19 version: 0.5.19(tailwindcss@3.4.19(yaml@2.8.2)) + '@types/nodemailer': + specifier: ^7.0.11 + version: 7.0.11 '@typescript-eslint/eslint-plugin': specifier: ^8.28.0 version: 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) @@ -1205,6 +1214,9 @@ packages: '@types/node@24.12.0': resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} + '@types/nodemailer@7.0.11': + resolution: {integrity: sha512-E+U4RzR2dKrx+u3N4DlsmLaDC6mMZOM/TPROxA0UAPiTgI0y4CEFBmZE+coGWTjakDriRsXG368lNk1u9Q0a2g==} + '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} @@ -2265,6 +2277,9 @@ packages: nlcst-to-string@4.0.0: resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + node-bin-setup@1.1.4: + resolution: {integrity: sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA==} + node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} @@ -2274,6 +2289,15 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node@25.8.2: + resolution: {integrity: sha512-ooLo0DWtJsL1qq7mv+bIn4HRjUou8PgFr8DqfXuXQOi/yRYrXX5+j82r4Pa6FJYXMBRmRql8Yjv+lVDdz268bQ==} + engines: {npm: '>=5.0.0'} + hasBin: true + + nodemailer@8.0.4: + resolution: {integrity: sha512-k+jf6N8PfQJ0Fe8ZhJlgqU5qJU44Lpvp2yvidH3vp1lPnVQMgi4yEEMPXg5eJS1gFIJTVq1NHBk7Ia9ARdSBdQ==} + engines: {node: '>=6.0.0'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -4047,6 +4071,10 @@ snapshots: dependencies: undici-types: 7.16.0 + '@types/nodemailer@7.0.11': + dependencies: + '@types/node': 24.12.0 + '@types/sax@1.2.7': dependencies: '@types/node': 24.12.0 @@ -5526,12 +5554,20 @@ snapshots: dependencies: '@types/nlcst': 2.0.3 + node-bin-setup@1.1.4: {} + node-fetch-native@1.6.7: {} node-mock-http@1.0.4: {} node-releases@2.0.27: {} + node@25.8.2: + dependencies: + node-bin-setup: 1.1.4 + + nodemailer@8.0.4: {} + normalize-path@3.0.0: {} nth-check@2.1.1: diff --git a/src/assets/mockups/cube_dashboard.png b/src/assets/mockups/cube_dashboard.png index d953d57..b941dd2 100644 Binary files a/src/assets/mockups/cube_dashboard.png and b/src/assets/mockups/cube_dashboard.png differ diff --git a/src/assets/mockups/prism_dashboard.png b/src/assets/mockups/prism_dashboard.png index 50afd39..652aaae 100644 Binary files a/src/assets/mockups/prism_dashboard.png and b/src/assets/mockups/prism_dashboard.png differ diff --git a/src/components/Footer.astro b/src/components/Footer.astro index a2412f5..1181b1b 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -5,7 +5,7 @@ const currentYear = new Date().getFullYear();