diff --git a/.env b/.env
index b99dca87..b62b5529 100644
--- a/.env
+++ b/.env
@@ -1 +1,2 @@
-DECO_SITE_NAME=starting
\ No newline at end of file
+DECO_SITE_NAME=starting
+DECO_ENV_NAME=estrangeiro
\ No newline at end of file
diff --git a/fresh.gen.ts b/fresh.gen.ts
index 3fb32afb..e5a83c5f 100644
--- a/fresh.gen.ts
+++ b/fresh.gen.ts
@@ -53,6 +53,7 @@ import * as $NRF_TextLines from "./islands/NRF/TextLines.tsx";
import * as $OnThisPage from "./islands/OnThisPage.tsx";
import * as $PopUp from "./islands/PopUp.tsx";
import * as $PopularDocuments from "./islands/PopularDocuments.tsx";
+import * as $PriceCalculatorIsland from "./islands/PriceCalculatorIsland.tsx";
import * as $Projects from "./islands/Projects.tsx";
import * as $RankingAnalyze from "./islands/RankingAnalyze.tsx";
import * as $RankingHeader from "./islands/RankingHeader.tsx";
@@ -123,6 +124,7 @@ const manifest = {
"./islands/OnThisPage.tsx": $OnThisPage,
"./islands/PopUp.tsx": $PopUp,
"./islands/PopularDocuments.tsx": $PopularDocuments,
+ "./islands/PriceCalculatorIsland.tsx": $PriceCalculatorIsland,
"./islands/Projects.tsx": $Projects,
"./islands/RankingAnalyze.tsx": $RankingAnalyze,
"./islands/RankingHeader.tsx": $RankingHeader,
diff --git a/islands/PriceCalculatorIsland.tsx b/islands/PriceCalculatorIsland.tsx
new file mode 100644
index 00000000..460c90aa
--- /dev/null
+++ b/islands/PriceCalculatorIsland.tsx
@@ -0,0 +1,660 @@
+import { useState, useEffect } from "preact/hooks";
+
+interface INPUT {
+ plan: string;
+ hosting: string;
+ builder_seats: number;
+ content_editor_seats: number;
+ general_seats: number;
+ infrastructure: string;
+ pageviews: number;
+ support: string;
+}
+
+export default function PriceCalculatorIsland() {
+ const [inputs, setInputs] = useState({
+ currency: "BRL",
+ plan: "enterprise",
+ hosting: "cloud",
+ builder_seats: 0,
+ content_editor_seats: 0,
+ general_seats: 0,
+ infrastructure: "efficient",
+ pageviews: 0,
+ support: "free",
+ });
+
+ const [estimatedCost, setEstimatedCost] = useState({
+ infrastructure: {
+ total: 0,
+ bandwidth: 0,
+ request: 0,
+ },
+ efficiency: {
+ not_optimized: 0,
+ efficient: 0,
+ medium_efficiency: 0,
+ },
+ seats: 0,
+ support: 0,
+ total: 0,
+ });
+
+ function updateCosts() {
+ const infrastructureCost = calculateInfrastructure(inputs);
+ const { total, bandwidth, request } =
+ infrastructureCost.selectedInfrastructure ||
+ { total: 0, bandwidth: 0, request: 0 };
+ const seatsCost = calculateSeats(inputs);
+ const supportCost = calculateSupport(inputs);
+
+ const totalCost = seatsCost + total + supportCost;
+
+ const updatedCost = {
+ ...estimatedCost,
+ infrastructure: {
+ total,
+ bandwidth,
+ request,
+ },
+ efficiency: {
+ not_optimized:
+ infrastructureCost.otherInfrastructures.not_optimized.total,
+ efficient: infrastructureCost.otherInfrastructures.efficient.total,
+ medium_efficiency:
+ infrastructureCost.otherInfrastructures.medium_efficiency.total,
+ },
+ seats: seatsCost,
+ support: supportCost,
+ total: totalCost,
+ };
+ setEstimatedCost(updatedCost);
+ }
+
+ useEffect(() => {
+ updateCosts();
+ }, [inputs]);
+
+ // Reusable input style
+ const inputStyle =
+ "w-full bg-black border border-gray-700 rounded-md p-2 text-white focus:border-emerald-400 focus:outline-none focus:ring-1 focus:ring-emerald-400";
+
+ return (
+
+
+
+
+ Calculadora de preços deco.cx
+
+
+
+ {/* Left Column - Configurations */}
+
+
Configurações
+
+
+ {/* Currency Selection */}
+
+ Moeda
+
+ setInputs({ ...inputs, currency: e.target.value })}
+ >
+ BRL (R$)
+
+
+
+ {/* Plans */}
+
+
Planos
+
+ Não sabe qual é para você? Veja os{" "}
+
+ recursos incluídos
+ {" "}
+ em cada plano.
+
+
+ {
+ setInputs({ ...inputs, plan: "enterprise" });
+ updateCosts();
+ }}
+ >
+ Enterprise
+
+ {
+ setInputs({ ...inputs, plan: "pro" });
+ updateCosts();
+ }}
+ >
+ Pro
+
+
+
+
+
+ {/* License Inputs */}
+
+
+
+ No. de licenças - Builder
+
+
+ Acesso irrestrito para desenvolver e orquestrar
+
+
{
+ setInputs({
+ ...inputs,
+ builder_seats: value.currentTarget.valueAsNumber,
+ });
+ updateCosts();
+ }}
+ />
+
+
+
+ No. de licenças - Content Editor
+
+
+ Acesso para editar conteúdos e utilizar dados
+
+
{
+ setInputs({
+ ...inputs,
+ content_editor_seats:
+ event.currentTarget.valueAsNumber,
+ });
+ updateCosts();
+ }}
+ />
+
+
+
+
+
+
+
+ No. de licenças - Content Editor
+
+
+ Acesso para editar conteúdos e utilizar dados
+
+
{
+ setInputs({
+ ...inputs,
+ general_seats: event.currentTarget.valueAsNumber,
+ });
+ updateCosts();
+ }}
+ />
+
+
+
+ {/* Infrastructure */}
+
+
Infraestrutura
+
+ Escolha entre infra 100% gerenciada ou hospede projetos você
+ mesmo.
+
+
+ {
+ setInputs({ ...inputs, hosting: "cloud" });
+ updateCosts();
+ }}
+ defaultChecked
+ >
+ deco Cloud
+
+ {
+ setInputs({ ...inputs, hosting: "self" });
+ updateCosts();
+ }}
+ >
+ Self-Hosting
+
+
+
+
+ {/* Pageviews */}
+
+
+ Pageviews mensais esperados
+
+
+ Para calcular multiplique sessões por média de páginas
+ visitadas / sessão
+
+
{
+ setInputs({
+ ...inputs,
+ pageviews: event.currentTarget.valueAsNumber,
+ });
+ updateCosts();
+ }}
+ />
+
+ Nota: Embora o custo agora seja calculado com base em
+ requisições e consumo de banda, pedimos a média de pageviews
+ mensais porque é mais fácil de estimar, especialmente para
+ novos clientes. Usaremos esse número como uma referência para
+ simulações e projeções de custos.
+
+
+
+ {/* Support Packages */}
+
+
+ Pacotes de suporte
+
+
+ Não sabe qual é para você? Veja os{" "}
+
+ recursos incluídos
+ {" "}
+ em cada pacote.
+
+
+ {
+ setInputs({ ...inputs, support: "free" });
+ updateCosts();
+ }}
+ >
+ Free
+
+ {
+ setInputs({ ...inputs, support: "premium" });
+ updateCosts();
+ }}
+ >
+ Premium
+
+ {
+ setInputs({ ...inputs, support: "enterprise" });
+ updateCosts();
+ }}
+ >
+ Enterprise
+
+
+
+
+
+
+ {/* Right Column - Estimated Costs */}
+
+
Custos estimados
+
+
+ {/* License Cost */}
+
+ Licenciamento de seats
+
+ {formatToReal(estimatedCost.seats)}
+
+
+
+ {/* Infrastructure */}
+
+
+
Infraestrutura
+
+
+ {formatToReal(estimatedCost.infrastructure.total)}
+
+
+
+
+ Fale com o nosso time de vendas
+
+
+
+
+
+
+
+ {/* Support */}
+
+ Suporte
+
+ {formatToReal(estimatedCost.support)}
+
+
+
+ {/* Total Cost */}
+
+
+ Custo Mensal Total
+
+ {formatToReal(estimatedCost.total)}
+
+
+
+
+
+ {/* Infrastructure Efficiency Scenarios */}
+
+
+ Cenários de eficiência da infraestrutura
+
+
+
+
+ Eficiente
+
+ ℹ️
+
+
+
+ {formatToReal(estimatedCost.efficiency.efficient)}
+
+
+
+
+ Eficiência média
+
+ ℹ️
+
+
+
+ {formatToReal(estimatedCost.efficiency.medium_efficiency)}
+
+
+
+
+ Não otimizado
+
+ ℹ️
+
+
+
+ {formatToReal(estimatedCost.efficiency.not_optimized)}
+
+
+
+
+
+
+
+
+ );
+}
+
+const EFFICIENTY_COSTS = {
+ not_optimized: {
+ bandwidth: 1.0405,
+ request: 10.119375,
+ },
+ medium_efficiency: {
+ bandwidth: 0.7,
+ request: 8.601192,
+ },
+ efficient: {
+ bandwidth: 0.25,
+ request: 6.977226,
+ },
+};
+
+function calculateSeats(inputs: INPUT) {
+ const { plan, builder_seats, content_editor_seats, general_seats } = inputs;
+
+ let seats = 0;
+
+ if (plan === "enterprise") {
+ /// Builder
+ if (builder_seats > 100) {
+ seats += builder_seats * 250;
+ } else if (builder_seats > 50) {
+ seats += 25000;
+ } else if (builder_seats > 20) {
+ seats += 15000;
+ } else if (builder_seats > 10) {
+ seats += 7000;
+ } else if (builder_seats > 5) {
+ seats += 4000;
+ } else if (builder_seats > 1) {
+ seats += 2250;
+ } else if (builder_seats === 1) {
+ seats += 500;
+ }
+
+ /// Content Editor
+ if (content_editor_seats > 100) {
+ seats += content_editor_seats * 125;
+ } else if (content_editor_seats > 50) {
+ seats += 12500;
+ } else if (content_editor_seats > 20) {
+ seats += 7500;
+ } else if (content_editor_seats > 10) {
+ seats += 3500;
+ } else if (content_editor_seats > 5) {
+ seats += 2000;
+ } else if (content_editor_seats > 1) {
+ seats += 1125;
+ } else if (content_editor_seats === 1) {
+ seats += 250;
+ }
+ } else {
+ if (general_seats > 100) {
+ seats += 30 * general_seats;
+ } else if (general_seats > 50) {
+ seats += 3000;
+ } else if (general_seats > 20) {
+ seats += 1750;
+ } else if (general_seats > 10) {
+ seats += 800;
+ } else if (general_seats > 5) {
+ seats += 450;
+ } else if (general_seats > 1) {
+ seats += 250;
+ } else if (general_seats === 1) {
+ seats += 55;
+ }
+ }
+
+ return seats;
+}
+
+function calculateInfrastructure(inputs: INPUT) {
+ let { pageviews, infrastructure, hosting } = inputs;
+
+ if (isNaN(pageviews)) {
+ pageviews = 0;
+ }
+
+ const result = {
+ not_optimized: calculateScenario(pageviews, "not_optimized"),
+ medium_efficiency: calculateScenario(pageviews, "medium_efficiency"),
+ efficient: calculateScenario(pageviews, "efficient"),
+ };
+
+ const selectedInfrastructure = (hosting === "self")
+ ? { total: 0, bandwidth: 0, request: 0 }
+ : result[infrastructure];
+
+ return {
+ selectedInfrastructure,
+ otherInfrastructures: result,
+ };
+}
+
+function calculateScenario(pageviews: number, infrastructureType: string) {
+ const { bandwidth: bandwidthCost, request: requestCost } =
+ EFFICIENTY_COSTS[infrastructureType];
+
+ const bandwidth = pageviews * bandwidthCost;
+ const request = pageviews * requestCost * 0.0004;
+ const total = bandwidth + request;
+
+ return { total, bandwidth, request };
+}
+
+function calculateSupport(input: INPUT) {
+ const support = input.support;
+
+ let cost = 0;
+
+ switch (support) {
+ case "free":
+ cost = 0;
+ break;
+ case "premium":
+ cost = 5000;
+ break;
+ case "enterprise":
+ cost = 10000;
+ break;
+ }
+
+ return cost;
+}
+
+function formatToReal(value: number) {
+ return value.toLocaleString("pt-BR", {
+ style: "currency",
+ currency: "BRL",
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ });
+}
diff --git a/sections/priceCalculator.tsx b/sections/priceCalculator.tsx
index 40ac0f5b..97ce60fb 100644
--- a/sections/priceCalculator.tsx
+++ b/sections/priceCalculator.tsx
@@ -1,14 +1,5 @@
-interface Props {
- /**
- * @description The description of name.
- */
- calculatorHTML: string;
-}
+import PriceCalculatorIsland from "site/islands/PriceCalculatorIsland.tsx";
-export default function Section({ calculatorHTML }: Props) {
- return (
-
- )
+export default function Section() {
+ return ;
}
\ No newline at end of file
diff --git a/static/tailwind.css b/static/tailwind.css
index e6500a35..3e8a363d 100644
--- a/static/tailwind.css
+++ b/static/tailwind.css
@@ -8865,6 +8865,11 @@ details.collapse summary::-webkit-details-marker {
margin-right: calc(0.75rem * var(--tw-space-x-reverse));
margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
}
+.space-x-4 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-x-reverse: 0;
+ margin-right: calc(1rem * var(--tw-space-x-reverse));
+ margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
+}
.space-x-6 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(1.5rem * var(--tw-space-x-reverse));
@@ -9361,6 +9366,10 @@ details.collapse summary::-webkit-details-marker {
--tw-border-opacity: 1;
border-color: rgb(10 33 33 / var(--tw-border-opacity));
}
+.border-emerald-400 {
+ --tw-border-opacity: 1;
+ border-color: rgb(52 211 153 / var(--tw-border-opacity));
+}
.border-gray-200 {
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity));
@@ -9373,6 +9382,10 @@ details.collapse summary::-webkit-details-marker {
--tw-border-opacity: 1;
border-color: rgb(156 163 175 / var(--tw-border-opacity));
}
+.border-gray-700 {
+ --tw-border-opacity: 1;
+ border-color: rgb(55 65 81 / var(--tw-border-opacity));
+}
.border-gray-800 {
--tw-border-opacity: 1;
border-color: rgb(31 41 55 / var(--tw-border-opacity));
@@ -9711,6 +9724,9 @@ details.collapse summary::-webkit-details-marker {
--tw-bg-opacity: 1;
background-color: rgb(218 143 255 / var(--tw-bg-opacity));
}
+.bg-emerald-400\/10 {
+ background-color: rgb(52 211 153 / 0.1);
+}
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
@@ -10509,6 +10525,9 @@ details.collapse summary::-webkit-details-marker {
.font-inter {
font-family: Inter, sans-serif;
}
+.font-mono {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+}
.font-sans {
font-family: Albert Sans, sans-serif;
}
@@ -10967,6 +10986,9 @@ details.collapse summary::-webkit-details-marker {
.tracking-wide {
letter-spacing: 0.025em;
}
+.tracking-wider {
+ letter-spacing: 0.05em;
+}
.\!text-\[\#F9FAFB\] {
--tw-text-opacity: 1 !important;
color: rgb(249 250 251 / var(--tw-text-opacity)) !important;
@@ -11229,6 +11251,10 @@ details.collapse summary::-webkit-details-marker {
--tw-text-opacity: 1;
color: rgb(2 246 124 / var(--tw-text-opacity));
}
+.text-emerald-400 {
+ --tw-text-opacity: 1;
+ color: rgb(52 211 153 / var(--tw-text-opacity));
+}
.text-frame-515-rgba {
color: rgba(31, 38, 31, 0.67);
}
@@ -11396,6 +11422,9 @@ details.collapse summary::-webkit-details-marker {
--tw-placeholder-opacity: 1;
color: rgb(255 255 255 / var(--tw-placeholder-opacity));
}
+.accent-emerald-400 {
+ accent-color: #34d399;
+}
.opacity-0 {
opacity: 0;
}
@@ -12718,11 +12747,27 @@ select.light-autofill:-webkit-autofill:focus {
border-color: rgb(0 0 0 / var(--tw-border-opacity));
}
+.focus\:border-emerald-400:focus {
+ --tw-border-opacity: 1;
+ border-color: rgb(52 211 153 / var(--tw-border-opacity));
+}
+
.focus\:outline-none:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
+.focus\:ring-1:focus {
+ --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
+}
+
+.focus\:ring-emerald-400:focus {
+ --tw-ring-opacity: 1;
+ --tw-ring-color: rgb(52 211 153 / var(--tw-ring-opacity));
+}
+
.focus\:ring-indigo-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));