Compare commits
2 Commits
feaa5e6f62
...
c9182795aa
| Author | SHA1 | Date | |
|---|---|---|---|
| c9182795aa | |||
| a392451cc6 |
+650
-71
@@ -7,10 +7,18 @@
|
||||
name="description"
|
||||
content="Odoo hosting, AI consulting and N8N automation. Reliable Odoo CE and Enterprise hosting with expert support, custom modules, and smart workflows."
|
||||
/>
|
||||
<title>ODOO4projects | Odoo Hosting, AI Consulting & N8N Automation</title>
|
||||
<title>
|
||||
ODOO4projects | Odoo Hosting, AI Consulting & N8N Automation
|
||||
</title>
|
||||
<link rel="canonical" href="https://ODOO4projects.com/" />
|
||||
<meta property="og:title" content="ODOO4projects | Odoo Hosting, AI Consulting & N8N Automation" />
|
||||
<meta property="og:description" content="Odoo hosting, AI consulting and N8N automation. Reliable Odoo CE and Enterprise hosting with expert support, custom modules, and smart workflows." />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="ODOO4projects | Odoo Hosting, AI Consulting & N8N Automation"
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Odoo hosting, AI consulting and N8N automation. Reliable Odoo CE and Enterprise hosting with expert support, custom modules, and smart workflows."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://ODOO4projects.com/" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
@@ -28,9 +36,7 @@
|
||||
"contactType": "customer support",
|
||||
"url": "https://ODOO4projects.com/contactus"
|
||||
},
|
||||
"sameAs": [
|
||||
"https://www.linkedin.com/company/odooprojects"
|
||||
]
|
||||
"sameAs": ["https://www.linkedin.com/company/odooprojects"]
|
||||
}
|
||||
</script>
|
||||
<script type="application/ld+json">
|
||||
@@ -43,8 +49,16 @@
|
||||
</script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap" />
|
||||
<link rel="preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||
<link
|
||||
rel="preload"
|
||||
as="style"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
as="style"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Inter+Tight:wght@500;600;700;800&display=swap"
|
||||
@@ -677,6 +691,70 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Billing Toggle ---- */
|
||||
.billing-toggle-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.toggle-label {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
color: rgba(33, 37, 41, 0.6);
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
user-select: none;
|
||||
}
|
||||
.toggle-label.active {
|
||||
color: var(--dark);
|
||||
font-weight: 600;
|
||||
}
|
||||
.toggle-label small {
|
||||
display: block;
|
||||
font-size: 0.62rem;
|
||||
font-weight: 400;
|
||||
color: #28a745;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
.toggle-switch {
|
||||
width: 48px;
|
||||
height: 26px;
|
||||
background: var(--border);
|
||||
border-radius: 13px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: background 0.25s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.toggle-switch.yearly {
|
||||
background: var(--primary);
|
||||
}
|
||||
.toggle-switch .thumb {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 3px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
transition: left 0.25s;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.toggle-switch.yearly .thumb {
|
||||
left: 25px;
|
||||
}
|
||||
.price-save {
|
||||
font-size: 0.6rem;
|
||||
font-weight: 700;
|
||||
color: #28a745;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
.price-period {
|
||||
color: rgba(33, 37, 41, 0.55);
|
||||
font-size: 0.68rem;
|
||||
}
|
||||
/* ---- Blog Section ---- */
|
||||
.blog-section {
|
||||
padding: 3rem 0;
|
||||
@@ -732,7 +810,10 @@
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||
transition:
|
||||
transform 0.2s,
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
}
|
||||
.blog-card:hover {
|
||||
transform: translateY(-2px);
|
||||
@@ -787,7 +868,7 @@
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.blog-card h3 {
|
||||
font-family: 'Inter Tight', sans-serif;
|
||||
font-family: "Inter Tight", sans-serif;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 0.5rem;
|
||||
@@ -842,7 +923,9 @@
|
||||
color: #e8e8f0;
|
||||
cursor: pointer;
|
||||
font-family: Inter, sans-serif;
|
||||
transition: border-color 0.2s, background 0.2s;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
background 0.2s;
|
||||
}
|
||||
.blog-page-btn:hover:not(:disabled) {
|
||||
border-color: #00f5ff;
|
||||
@@ -891,7 +974,17 @@
|
||||
free trial — no credit card required!
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn btn-primary" href="/contactus"
|
||||
<a
|
||||
class="btn btn-primary btn-lg"
|
||||
href="javascript:void(0)"
|
||||
onclick="
|
||||
openOrderWidget(
|
||||
'On the Rise',
|
||||
36.21,
|
||||
395.0,
|
||||
false,
|
||||
)
|
||||
"
|
||||
>Try Now</a
|
||||
>
|
||||
</p>
|
||||
@@ -1028,7 +1121,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="pop"
|
||||
id="orderWidgetOverlay"
|
||||
style="
|
||||
display: none;
|
||||
position: fixed;
|
||||
@@ -1039,6 +1132,8 @@
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<!-- Buy Panel (shown on manual button clicks) -->
|
||||
<div id="orderPanelBuy" style="display: none">
|
||||
<div
|
||||
style="
|
||||
background: #fff;
|
||||
@@ -1046,11 +1141,11 @@
|
||||
max-width: 460px;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
"
|
||||
>
|
||||
<div style="position: relative">
|
||||
<button
|
||||
onclick="closepop()"
|
||||
onclick="closeOrderWidget()"
|
||||
style="
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
@@ -1069,7 +1164,165 @@
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div style="padding: 2rem; text-align: center; border-radius: 0.8rem;">
|
||||
<div style="padding: 2rem">
|
||||
<h2
|
||||
style="
|
||||
font-size: clamp(1rem, 2vw, 1.24rem);
|
||||
margin-bottom: 0.5rem;
|
||||
color: #1b1319;
|
||||
"
|
||||
id="orderPlanTitle"
|
||||
>
|
||||
On the Rise
|
||||
</h2>
|
||||
<p
|
||||
style="
|
||||
font-size: 0.8rem;
|
||||
color: rgba(33, 37, 41, 0.6);
|
||||
margin-bottom: 1rem;
|
||||
"
|
||||
>
|
||||
<span id="orderPlanPrice">$ 36.21</span>
|
||||
<span id="orderPlanPeriod">/ month</span>
|
||||
<span
|
||||
id="orderPlanTax"
|
||||
style="
|
||||
font-size: 0.7rem;
|
||||
color: rgba(33, 37, 41, 0.45);
|
||||
"
|
||||
>
|
||||
+ tax</span
|
||||
>
|
||||
</p>
|
||||
<p
|
||||
id="orderCouponMsg"
|
||||
style="
|
||||
font-size: 0.78rem;
|
||||
color: #28a745;
|
||||
margin-bottom: 1rem;
|
||||
display: none;
|
||||
"
|
||||
>
|
||||
Use coupon <strong>FREE TRIAL</strong> at checkout
|
||||
for 1 month free
|
||||
</p>
|
||||
<p
|
||||
id="orderYearlySave"
|
||||
style="
|
||||
font-size: 0.78rem;
|
||||
color: #28a745;
|
||||
margin-bottom: 1rem;
|
||||
display: none;
|
||||
"
|
||||
>
|
||||
Save <span id="orderSavePercent">15</span>% with
|
||||
yearly billing
|
||||
</p>
|
||||
<label
|
||||
style="
|
||||
font-size: 0.78rem;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
color: #1b1319;
|
||||
"
|
||||
>Server Location</label
|
||||
>
|
||||
<select
|
||||
id="orderServerLocation"
|
||||
style="
|
||||
width: 100%;
|
||||
padding: 0.6rem 0.8rem;
|
||||
font-size: 0.82rem;
|
||||
border: 1px solid #e5e3e0;
|
||||
border-radius: 0.5rem;
|
||||
background: #fff;
|
||||
color: #1b1319;
|
||||
margin-bottom: 1.5rem;
|
||||
font-family: Inter, sans-serif;
|
||||
cursor: pointer;
|
||||
"
|
||||
>
|
||||
<option value="USA">
|
||||
🇺🇸 United States
|
||||
</option>
|
||||
<option value="Brazil">
|
||||
🇧🇷 Brazil
|
||||
</option>
|
||||
<option value="India">
|
||||
🇮🇳 India
|
||||
</option>
|
||||
<option value="Australia">
|
||||
🇦🇺 Australia
|
||||
</option>
|
||||
<option value="Netherlands">
|
||||
🇳🇱 Netherlands
|
||||
</option>
|
||||
<option value="UK">
|
||||
🇬🇧 United Kingdom
|
||||
</option>
|
||||
</select>
|
||||
<a
|
||||
id="orderBuyBtn"
|
||||
href="/contactus"
|
||||
class="btn btn-primary btn-lg"
|
||||
style="
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
display: block;
|
||||
"
|
||||
>
|
||||
Continue to Stripe →
|
||||
</a>
|
||||
<p
|
||||
style="
|
||||
font-size: 0.68rem;
|
||||
color: rgba(33, 37, 41, 0.45);
|
||||
text-align: center;
|
||||
margin-top: 0.6rem;
|
||||
"
|
||||
>
|
||||
🔒 Secure Stripe checkout · Credit
|
||||
card required
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Free Trial Panel (shown on automatic scroll popup) -->
|
||||
<div id="orderPanelTrial" style="display: none">
|
||||
<div
|
||||
style="
|
||||
background: #fff;
|
||||
border-radius: 1rem;
|
||||
max-width: 460px;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
"
|
||||
>
|
||||
<button
|
||||
onclick="closeOrderWidget()"
|
||||
style="
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
right: 0.75rem;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
border: none;
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
font-size: 1.3rem;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
color: #555;
|
||||
"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div style="padding: 2rem 2rem 1.5rem">
|
||||
<h2
|
||||
style="
|
||||
font-size: clamp(1rem, 2vw, 1.24rem);
|
||||
@@ -1083,14 +1336,32 @@
|
||||
style="
|
||||
font-size: 0.8rem;
|
||||
color: rgba(33, 37, 41, 0.7);
|
||||
margin-bottom: 1.5rem;
|
||||
"
|
||||
>
|
||||
No credit card required
|
||||
Credit card required · Cancel anytime
|
||||
</p>
|
||||
<a class="btn btn-primary btn-lg" href="/contactus"
|
||||
>Try Now</a
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="btn btn-primary btn-lg"
|
||||
onclick="switchToBuyPanel()"
|
||||
style="
|
||||
background: #714b67;
|
||||
border-color: #714b67;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
"
|
||||
>Select a Plan</a
|
||||
>
|
||||
</div>
|
||||
<p
|
||||
style="
|
||||
font-size: 0.68rem;
|
||||
color: rgba(33, 37, 41, 0.45);
|
||||
margin-top: 0.8rem;
|
||||
"
|
||||
>
|
||||
🔒 Secure · No commitment
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1100,8 +1371,8 @@
|
||||
<div class="container">
|
||||
<div class="hr"></div>
|
||||
<h1>
|
||||
Effortless Odoo Community Hosting with AI-Powered Automation —
|
||||
Scale Your Business Seamlessly
|
||||
Effortless Odoo Community Hosting with AI-Powered Automation
|
||||
— Scale Your Business Seamlessly
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1238,21 +1509,48 @@
|
||||
<div class="hr"></div>
|
||||
<h2>Your Plan, Your Timing: Upgrade Anytime</h2>
|
||||
</div>
|
||||
<div class="billing-toggle-wrap">
|
||||
<span class="toggle-label toggle-label-monthly active"
|
||||
>Monthly</span
|
||||
>
|
||||
<div class="toggle-switch" id="billingSwitch">
|
||||
<div class="thumb"></div>
|
||||
</div>
|
||||
<span class="toggle-label toggle-label-yearly"
|
||||
>Yearly <small>1 month free</small></span
|
||||
>
|
||||
</div>
|
||||
<div class="pgrid">
|
||||
<div class="pcard">
|
||||
<div class="pcard-body">
|
||||
<h3>Side Hustle</h3>
|
||||
<div class="price">
|
||||
<strong>$ 214.00</strong>
|
||||
<small class="text-muted">/ year</small>
|
||||
<strong
|
||||
class="price-amount"
|
||||
data-monthly="19.62"
|
||||
data-yearly="214.00"
|
||||
>$ 19.62</strong
|
||||
>
|
||||
<small class="price-period">/ month</small>
|
||||
<div class="price-save" style="display: none">
|
||||
1 month free
|
||||
</div>
|
||||
</div>
|
||||
<p class="desc">
|
||||
“ODOO Standard .. that is all my business
|
||||
needs”
|
||||
</p>
|
||||
<a
|
||||
href="/3/214.00/4/Side%20Hustle"
|
||||
href="javascript:void(0)"
|
||||
class="btn btn-primary"
|
||||
onclick="
|
||||
openOrderWidget(
|
||||
'Side Hustle',
|
||||
19.62,
|
||||
214.0,
|
||||
false,
|
||||
)
|
||||
"
|
||||
>Buy Now</a
|
||||
>
|
||||
<ul>
|
||||
@@ -1294,16 +1592,32 @@
|
||||
<div class="pcard-body">
|
||||
<h3>On the Rise</h3>
|
||||
<div class="price">
|
||||
<strong>$ 395.00</strong>
|
||||
<small class="text-muted">/ year</small>
|
||||
<strong
|
||||
class="price-amount"
|
||||
data-monthly="36.21"
|
||||
data-yearly="395.00"
|
||||
>$ 36.21</strong
|
||||
>
|
||||
<small class="price-period">/ month</small>
|
||||
<div class="price-save" style="display: none">
|
||||
1 month free
|
||||
</div>
|
||||
</div>
|
||||
<p class="desc">
|
||||
“I need some modules and professional
|
||||
reports”
|
||||
</p>
|
||||
<a
|
||||
href="/4/395.00/4/On%20the%20Rise"
|
||||
href="javascript:void(0)"
|
||||
class="btn btn-primary"
|
||||
onclick="
|
||||
openOrderWidget(
|
||||
'On the Rise',
|
||||
36.21,
|
||||
395.0,
|
||||
false,
|
||||
)
|
||||
"
|
||||
>Buy Now</a
|
||||
>
|
||||
<ul>
|
||||
@@ -1345,15 +1659,31 @@
|
||||
<div class="pcard-body">
|
||||
<h3>Powerhouse</h3>
|
||||
<div class="price">
|
||||
<strong>$ 595.00</strong>
|
||||
<small class="text-muted">/ year</small>
|
||||
<strong
|
||||
class="price-amount"
|
||||
data-monthly="54.54"
|
||||
data-yearly="595.00"
|
||||
>$ 54.54</strong
|
||||
>
|
||||
<small class="price-period">/ month</small>
|
||||
<div class="price-save" style="display: none">
|
||||
1 month free
|
||||
</div>
|
||||
</div>
|
||||
<p class="desc">
|
||||
“ODOO Enterprise is a must have!”
|
||||
</p>
|
||||
<a
|
||||
href="/5/595.00/4/Powerhouse"
|
||||
href="javascript:void(0)"
|
||||
class="btn btn-primary"
|
||||
onclick="
|
||||
openOrderWidget(
|
||||
'Powerhouse',
|
||||
54.54,
|
||||
595.0,
|
||||
false,
|
||||
)
|
||||
"
|
||||
>Buy Now</a
|
||||
>
|
||||
<ul>
|
||||
@@ -1389,13 +1719,31 @@
|
||||
<div class="pcard-body">
|
||||
<h3>Empire</h3>
|
||||
<div class="price">
|
||||
<strong>>$ 950.00</strong>
|
||||
<small class="text-muted">/ year</small>
|
||||
<strong
|
||||
class="price-amount"
|
||||
data-monthly="86.67"
|
||||
data-yearly="950.00"
|
||||
>>$ 86.67</strong
|
||||
>
|
||||
<small class="price-period">/ month</small>
|
||||
<div class="price-save" style="display: none">
|
||||
1 month free
|
||||
</div>
|
||||
</div>
|
||||
<p class="desc">
|
||||
“My house! My Horse! My Server!”
|
||||
</p>
|
||||
<a href="/contactus" class="btn btn-outline-primary"
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
class="btn btn-outline-primary"
|
||||
onclick="
|
||||
openOrderWidget(
|
||||
'Empire',
|
||||
86.67,
|
||||
950.0,
|
||||
true,
|
||||
)
|
||||
"
|
||||
>Contact Us</a
|
||||
>
|
||||
<ul>
|
||||
@@ -1438,7 +1786,12 @@
|
||||
<h2>Latest from the Blog</h2>
|
||||
</div>
|
||||
<div class="blog-search-wrap">
|
||||
<input type="text" class="blog-search" id="blogSearch" placeholder="Search posts..." />
|
||||
<input
|
||||
type="text"
|
||||
class="blog-search"
|
||||
id="blogSearch"
|
||||
placeholder="Search posts..."
|
||||
/>
|
||||
</div>
|
||||
<div class="blog-grid" id="blogGrid"></div>
|
||||
<div class="blog-pagination" id="blogPagination"></div>
|
||||
@@ -1657,16 +2010,18 @@
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
document.getElementById("pop").style.display = "flex";
|
||||
}, 5000);
|
||||
function closepop() {
|
||||
document.getElementById("pop").style.display = "none";
|
||||
var blogSection = document.getElementById("blog");
|
||||
if (blogSection) {
|
||||
function onBlogScroll() {
|
||||
var rect = blogSection.getBoundingClientRect();
|
||||
if (rect.top < window.innerHeight && rect.bottom > 0) {
|
||||
openTrialWidget();
|
||||
window.removeEventListener("scroll", onBlogScroll);
|
||||
}
|
||||
document
|
||||
.getElementById("pop")
|
||||
.addEventListener("click", function (e) {
|
||||
if (e.target === this) closepop();
|
||||
});
|
||||
}
|
||||
window.addEventListener("scroll", onBlogScroll);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
document.querySelectorAll(".tab-btn").forEach(function (b) {
|
||||
b.addEventListener("click", function () {
|
||||
@@ -1685,57 +2040,249 @@
|
||||
});
|
||||
});
|
||||
|
||||
/* ---- Order Widget ---- */
|
||||
var orderPopupShown = false;
|
||||
function openOrderWidget(
|
||||
plan,
|
||||
monthlyPrice,
|
||||
yearlyPrice,
|
||||
isEmpire,
|
||||
) {
|
||||
document.getElementById("orderPanelTrial").style.display =
|
||||
"none";
|
||||
document.getElementById("orderPanelBuy").style.display =
|
||||
"block";
|
||||
var widget = document.getElementById("orderWidgetOverlay");
|
||||
document.getElementById("orderPlanTitle").textContent = plan;
|
||||
var yearly = yearlyMode;
|
||||
var price = yearly ? yearlyPrice : monthlyPrice;
|
||||
var amountEl = document.getElementById("orderPlanPrice");
|
||||
var prefix = isEmpire ? ">$" : "$";
|
||||
amountEl.textContent = prefix + " " + price.toFixed(2);
|
||||
document.getElementById("orderPlanPeriod").textContent = yearly
|
||||
? "/ year"
|
||||
: "/ month";
|
||||
var couponMsg = document.getElementById("orderCouponMsg");
|
||||
var yearlySave = document.getElementById("orderYearlySave");
|
||||
if (!yearly) {
|
||||
couponMsg.style.display = "block";
|
||||
yearlySave.style.display = "none";
|
||||
} else {
|
||||
couponMsg.style.display = "none";
|
||||
yearlySave.style.display = "block";
|
||||
var saved = Math.round(
|
||||
(1 - yearlyPrice / (monthlyPrice * 12)) * 100,
|
||||
);
|
||||
document.getElementById("orderSavePercent").textContent =
|
||||
saved;
|
||||
}
|
||||
var buyBtn = document.getElementById("orderBuyBtn");
|
||||
var loc = document.getElementById("orderServerLocation").value;
|
||||
buyBtn.href =
|
||||
"/3/" +
|
||||
price.toFixed(2) +
|
||||
"/4/" +
|
||||
encodeURIComponent(plan) +
|
||||
"?location=" +
|
||||
encodeURIComponent(loc);
|
||||
widget.style.display = "flex";
|
||||
orderPopupShown = true;
|
||||
}
|
||||
function openTrialWidget() {
|
||||
document.getElementById("orderPanelBuy").style.display = "none";
|
||||
document.getElementById("orderPanelTrial").style.display =
|
||||
"block";
|
||||
document.getElementById("orderWidgetOverlay").style.display =
|
||||
"flex";
|
||||
orderPopupShown = true;
|
||||
}
|
||||
function switchToBuyPanel() {
|
||||
openOrderWidget("On the Rise", 36.21, 395.0, false);
|
||||
}
|
||||
function closeOrderWidget() {
|
||||
document.getElementById("orderWidgetOverlay").style.display =
|
||||
"none";
|
||||
}
|
||||
document
|
||||
.getElementById("orderServerLocation")
|
||||
.addEventListener("change", function () {
|
||||
var plan =
|
||||
document.getElementById("orderPlanTitle").textContent;
|
||||
var priceText = document
|
||||
.getElementById("orderPlanPrice")
|
||||
.textContent.replace(">$", "")
|
||||
.replace("$", "")
|
||||
.trim();
|
||||
var price = parseFloat(priceText);
|
||||
var loc = this.value;
|
||||
document.getElementById("orderBuyBtn").href =
|
||||
"/3/" +
|
||||
price.toFixed(2) +
|
||||
"/4/" +
|
||||
encodeURIComponent(plan) +
|
||||
"?location=" +
|
||||
encodeURIComponent(loc);
|
||||
});
|
||||
/* ---- Billing Toggle ---- */
|
||||
var yearlyMode = false;
|
||||
var biSwitch = document.getElementById("billingSwitch");
|
||||
var labels = document.querySelectorAll(".toggle-label");
|
||||
var monthlyLabel = document.querySelector(".toggle-label-monthly");
|
||||
var yearlyLabel = document.querySelector(".toggle-label-yearly");
|
||||
|
||||
function updatePrices(yearly) {
|
||||
var amounts = document.querySelectorAll(".price-amount");
|
||||
for (var k = 0; k < amounts.length; k++) {
|
||||
var el = amounts[k];
|
||||
var val = yearly
|
||||
? el.getAttribute("data-yearly")
|
||||
: el.getAttribute("data-monthly");
|
||||
var prefix =
|
||||
el.textContent.trim().charAt(0) === ">" ? ">" : "";
|
||||
el.textContent = prefix + "$ " + parseFloat(val).toFixed(2);
|
||||
}
|
||||
var periods = document.querySelectorAll(".price-period");
|
||||
for (var k = 0; k < periods.length; k++) {
|
||||
periods[k].textContent = yearly ? "/ year" : "/ month";
|
||||
}
|
||||
var saves = document.querySelectorAll(".price-save");
|
||||
for (var k = 0; k < saves.length; k++) {
|
||||
saves[k].style.display = yearly ? "block" : "none";
|
||||
}
|
||||
}
|
||||
|
||||
function setBilling(yearly) {
|
||||
yearlyMode = yearly;
|
||||
if (yearly) {
|
||||
biSwitch.classList.add("yearly");
|
||||
monthlyLabel.classList.remove("active");
|
||||
yearlyLabel.classList.add("active");
|
||||
} else {
|
||||
biSwitch.classList.remove("yearly");
|
||||
monthlyLabel.classList.add("active");
|
||||
yearlyLabel.classList.remove("active");
|
||||
}
|
||||
updatePrices(yearly);
|
||||
}
|
||||
|
||||
biSwitch.addEventListener("click", function () {
|
||||
setBilling(!yearlyMode);
|
||||
});
|
||||
monthlyLabel.addEventListener("click", function () {
|
||||
setBilling(false);
|
||||
});
|
||||
yearlyLabel.addEventListener("click", function () {
|
||||
setBilling(true);
|
||||
});
|
||||
|
||||
/* ---- Blog Module ---- */
|
||||
var blogState = {
|
||||
allPosts: [],
|
||||
filteredPosts: [],
|
||||
currentPage: 1,
|
||||
perPage: 6,
|
||||
searchTerm: ""
|
||||
searchTerm: "",
|
||||
};
|
||||
|
||||
function formatDate(dateStr) {
|
||||
var d = new Date(dateStr + "T00:00:00Z");
|
||||
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
return months[d.getUTCMonth()] + " " + d.getUTCDate() + ", " + d.getUTCFullYear();
|
||||
var months = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
return (
|
||||
months[d.getUTCMonth()] +
|
||||
" " +
|
||||
d.getUTCDate() +
|
||||
", " +
|
||||
d.getUTCFullYear()
|
||||
);
|
||||
}
|
||||
|
||||
function badgeClass(area) {
|
||||
var m = {"speed-run":"speed-run","guide":"guide","howto":"howto","news":"news"};
|
||||
var m = {
|
||||
"speed-run": "speed-run",
|
||||
guide: "guide",
|
||||
howto: "howto",
|
||||
news: "news",
|
||||
};
|
||||
return m[area] || "default";
|
||||
}
|
||||
|
||||
function renderBlog() {
|
||||
var grid = document.getElementById("blogGrid");
|
||||
var search = (blogState.searchTerm || "").toLowerCase();
|
||||
blogState.filteredPosts = blogState.allPosts.filter(function(p) {
|
||||
blogState.filteredPosts = blogState.allPosts.filter(
|
||||
function (p) {
|
||||
if (!search) return true;
|
||||
return (p.headline + " " + p.teaser).toLowerCase().indexOf(search) !== -1;
|
||||
});
|
||||
return (
|
||||
(p.headline + " " + p.teaser)
|
||||
.toLowerCase()
|
||||
.indexOf(search) !== -1
|
||||
);
|
||||
},
|
||||
);
|
||||
var total = blogState.filteredPosts.length;
|
||||
var totalPages = Math.max(1, Math.ceil(total / blogState.perPage));
|
||||
if (blogState.currentPage > totalPages) blogState.currentPage = totalPages;
|
||||
var totalPages = Math.max(
|
||||
1,
|
||||
Math.ceil(total / blogState.perPage),
|
||||
);
|
||||
if (blogState.currentPage > totalPages)
|
||||
blogState.currentPage = totalPages;
|
||||
var start = (blogState.currentPage - 1) * blogState.perPage;
|
||||
var pagePosts = blogState.filteredPosts.slice(start, start + blogState.perPage);
|
||||
var pagePosts = blogState.filteredPosts.slice(
|
||||
start,
|
||||
start + blogState.perPage,
|
||||
);
|
||||
|
||||
var html = "";
|
||||
if (pagePosts.length === 0) {
|
||||
html = "<div class=\"blog-empty\">No posts match your search.</div>";
|
||||
html =
|
||||
'<div class="blog-empty">No posts match your search.</div>';
|
||||
} else {
|
||||
for (var i = 0; i < pagePosts.length; i++) {
|
||||
var p = pagePosts[i];
|
||||
var bc = badgeClass(p.area);
|
||||
var agentHtml = "";
|
||||
if (p.agent) agentHtml = "<span class=\"blog-agent\">" + p.agent + "</span>";
|
||||
html += "<div class=\"blog-card\">" +
|
||||
"<div class=\"blog-card-top\">" +
|
||||
"<span class=\"blog-badge blog-badge-" + bc + "\">" + p.area + "</span>" +
|
||||
if (p.agent)
|
||||
agentHtml =
|
||||
'<span class="blog-agent">' +
|
||||
p.agent +
|
||||
"</span>";
|
||||
html +=
|
||||
'<div class="blog-card">' +
|
||||
'<div class="blog-card-top">' +
|
||||
'<span class="blog-badge blog-badge-' +
|
||||
bc +
|
||||
'">' +
|
||||
p.area +
|
||||
"</span>" +
|
||||
agentHtml +
|
||||
"</div>" +
|
||||
"<div class=\"blog-date\">" + formatDate(p.date) + "</div>" +
|
||||
"<h3><a href=\"" + p.link + "\">" + p.headline + "</a></h3>" +
|
||||
"<p class=\"blog-teaser\">" + p.teaser + "</p>" +
|
||||
"<a href=\"" + p.link + "\" class=\"blog-readmore\">Read more →</a>" +
|
||||
'<div class="blog-date">' +
|
||||
formatDate(p.date) +
|
||||
"</div>" +
|
||||
'<h3><a href="' +
|
||||
p.link +
|
||||
'">' +
|
||||
p.headline +
|
||||
"</a></h3>" +
|
||||
'<p class="blog-teaser">' +
|
||||
p.teaser +
|
||||
"</p>" +
|
||||
'<a href="' +
|
||||
p.link +
|
||||
'" class="blog-readmore">Read more →</a>' +
|
||||
"</div>";
|
||||
}
|
||||
}
|
||||
@@ -1744,11 +2291,38 @@
|
||||
var pag = document.getElementById("blogPagination");
|
||||
var pagHtml = "";
|
||||
if (totalPages > 1) {
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(1)\"" + (blogState.currentPage <= 1 ? " disabled\"" : "\"") + ">«</button>";
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(" + (blogState.currentPage - 1) + ")\"" + (blogState.currentPage <= 1 ? " disabled\"" : "\"") + ">‹ Prev</button>";
|
||||
pagHtml += "<span class=\"blog-page-info\">Page " + blogState.currentPage + " of " + totalPages + "</span>";
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(" + (blogState.currentPage + 1) + ")\"" + (blogState.currentPage >= totalPages ? " disabled\"" : "\"") + ">Next ›</button>";
|
||||
pagHtml += "<button class=\"blog-page-btn\" onclick=\"blogGo(" + totalPages + ")\"" + (blogState.currentPage >= totalPages ? " disabled\"" : "\"") + ">»</button>";
|
||||
pagHtml +=
|
||||
'<button class="blog-page-btn" onclick="blogGo(1)"' +
|
||||
(blogState.currentPage <= 1 ? ' disabled"' : '"') +
|
||||
">«</button>";
|
||||
pagHtml +=
|
||||
'<button class="blog-page-btn" onclick="blogGo(' +
|
||||
(blogState.currentPage - 1) +
|
||||
')"' +
|
||||
(blogState.currentPage <= 1 ? ' disabled"' : '"') +
|
||||
">‹ Prev</button>";
|
||||
pagHtml +=
|
||||
'<span class="blog-page-info">Page ' +
|
||||
blogState.currentPage +
|
||||
" of " +
|
||||
totalPages +
|
||||
"</span>";
|
||||
pagHtml +=
|
||||
'<button class="blog-page-btn" onclick="blogGo(' +
|
||||
(blogState.currentPage + 1) +
|
||||
')"' +
|
||||
(blogState.currentPage >= totalPages
|
||||
? ' disabled"'
|
||||
: '"') +
|
||||
">Next ›</button>";
|
||||
pagHtml +=
|
||||
'<button class="blog-page-btn" onclick="blogGo(' +
|
||||
totalPages +
|
||||
')"' +
|
||||
(blogState.currentPage >= totalPages
|
||||
? ' disabled"'
|
||||
: '"') +
|
||||
">»</button>";
|
||||
}
|
||||
pag.innerHTML = pagHtml;
|
||||
}
|
||||
@@ -1759,16 +2333,21 @@
|
||||
}
|
||||
|
||||
fetch("blog/index.json?_=" + Date.now())
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function (r) {
|
||||
return r.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
blogState.allPosts = data.posts;
|
||||
renderBlog();
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById("blogGrid").innerHTML = "<div class=\"blog-empty\">Could not load blog posts.</div>";
|
||||
document.getElementById("blogGrid").innerHTML =
|
||||
'<div class="blog-empty">Could not load blog posts.</div>';
|
||||
});
|
||||
|
||||
document.getElementById("blogSearch").addEventListener("input", function() {
|
||||
document
|
||||
.getElementById("blogSearch")
|
||||
.addEventListener("input", function () {
|
||||
blogState.searchTerm = this.value;
|
||||
blogState.currentPage = 1;
|
||||
renderBlog();
|
||||
|
||||
Reference in New Issue
Block a user