-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
304 lines (279 loc) · 16.8 KB
/
Copy pathindex.html
File metadata and controls
304 lines (279 loc) · 16.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Syncpoint Map Server — digitale Karten direkt von Deinem Windows Gerät. Ohne Cloud, ohne Internetverbindung, ohne laufende Kosten. Windows-native, MSI-Installer, MBTiles, PMTiles, COG, PostGIS.">
<title>Syncpoint Map Server</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="tabler/tabler-icons.css">
</head>
<body>
<nav>
<a class="nav-logo" href="#">
<div class="nav-logo-dot"></div>
Syncpoint Map Server
</a>
<div class="nav-right">
<div class="nav-links">
<a href="#features" data-de="Features" data-en="Features">Features</a>
<a href="#install" data-de="Installation" data-en="Installation">Installation</a>
<a href="#pricing" data-de="Preise" data-en="Pricing">Preise</a>
</div>
<div class="lang-toggle">
<button class="lang-btn" id="btn-de" onclick="setLang('de')">DE</button>
<button class="lang-btn" id="btn-en" onclick="setLang('en')">EN</button>
</div>
</div>
</nav>
<div class="hero">
<div class="badge" data-de="Windows · Laptop oder Server · Offline-first" data-en="Windows · Laptop or server · Offline-first"></div>
<h1 id="hero-title"></h1>
<p class="hero-sub" data-de="Syncpoint Map Server liefert digitale Karten direkt von Deinem Windows Gerät — ohne Cloud, ohne Internetverbindung, ohne laufende Kosten." data-en="Syncpoint Map Server serves map tiles directly from your Windows based device — no cloud, no internet connection, no recurring costs."></p>
<div class="cta-group">
<a href="#pricing" class="btn-primary" data-de="Jetzt kaufen" data-en="Buy now">Jetzt kaufen</a>
<a href="#features" class="btn-secondary" data-de="Mehr erfahren" data-en="Learn more">Mehr erfahren</a>
</div>
</div>
<div class="stats">
<div class="stat">
<div class="stat-val">5 min</div>
<div class="stat-lbl" data-de="bis zum ersten Tile" data-en="to your first tile"></div>
</div>
<div class="stat">
<div class="stat-val">0 €</div>
<div class="stat-lbl" data-de="laufende Kosten" data-en="recurring costs"></div>
</div>
<div class="stat">
<div class="stat-val" data-de="MBTiles · PMTiles · COG · PostGIS" data-en="MBTiles · PMTiles · COG · PostGIS"></div>
<div class="stat-lbl" data-de="unterstützte Datenquellen" data-en="supported data sources"></div>
</div>
<div class="stat">
<div class="stat-val">Offline-first</div>
<div class="stat-lbl" data-de="keine Verbindung zum Internet erforderlich" data-en="no internet connection required"></div>
</div>
</div>
<section id="features">
<div class="section-label" data-de="Features" data-en="Features"></div>
<h2 data-de="Alles was Du brauchst" data-en="Everything you need"></h2>
<p class="section-sub" data-de="Für alle, die digitale Karten unabhängig vom Internet nutzen wollen — ob auf dem Laptop im Gelände oder als Windows-Dienst auf dem Server." data-en="For anyone who wants to use digital maps independently of the internet — whether on a laptop in the field or as a Windows service on the server."></p>
<div class="features">
<div class="feature">
<div class="feature-icon"><i class="ti ti-device-laptop" aria-hidden="true"></i></div>
<h3 data-de="Laptop oder Server" data-en="Laptop or server"></h3>
<p data-de="Im Benutzerkontext läuft der Map Server als SysTray-App auf Deinem Windows-Gerät. Im Maschinenkontext als nativer Windows-Dienst." data-en="In user context, the map server runs as a system tray app on your Windows device. In machine context, as a native Windows service."></p>
</div>
<div class="feature">
<div class="feature-icon"><i class="ti ti-database" aria-hidden="true"></i></div>
<h3 data-de="Flexible Datenquellen" data-en="Flexible data sources"></h3>
<p data-de="Unterstützt MBTiles, PMTiles und Cloud Optimized GeoTIFF (COG) als Datei-Quellen sowie PostgreSQL/PostGIS für vektorbasierte Tile-Generierung direkt aus der Datenbank." data-en="Supports MBTiles, PMTiles, and Cloud Optimized GeoTIFF (COG) as file sources, as well as PostgreSQL/PostGIS for vector tile generation directly from the database."></p>
</div>
<div class="feature">
<div class="feature-icon"><i class="ti ti-brand-windows" aria-hidden="true"></i></div>
<h3 data-de="Native Windows-Integration" data-en="Native Windows integration"></h3>
<p data-de="Systray-Icon für Schnellzugriff. Dienst starten und stoppen ohne Terminal oder Kommandozeile." data-en="System tray icon for quick access. Start and stop without a terminal or command line."></p>
</div>
<div class="feature">
<div class="feature-icon"><i class="ti ti-settings" aria-hidden="true"></i></div>
<h3 data-de="Management UI" data-en="Management UI"></h3>
<p data-de="Datenbank-Ordner direkt aus dem Systray-Menü öffnen. MBTiles und PMTiles einfach ablegen — fertig." data-en="Open the database folder directly from the system tray menu. Drop in MBTiles or PMTiles files and you're done."></p>
</div>
<div class="feature">
<div class="feature-icon"><i class="ti ti-wifi-off" aria-hidden="true"></i></div>
<h3 data-de="Vollständig offline-fähig" data-en="Fully air-gap capable"></h3>
<p data-de="Kein Cloud-Endpoint, keine Telemetrie, keine Internetverbindung erforderlich." data-en="No cloud endpoint, no telemetry, no internet connection required."></p>
</div>
<div class="feature">
<div class="feature-icon"><i class="ti ti-refresh" aria-hidden="true"></i></div>
<h3 data-de="Lifetime Updates" data-en="Lifetime updates"></h3>
<p data-de="Einmalig kaufen, alle zukünftigen Versionen inklusive. Kein Abo, keine Verlängerungsgebühren." data-en="Buy once, all future versions included. No subscription, no renewal fees."></p>
</div>
</div>
</section>
<hr class="divider">
<section id="install">
<div class="section-label" data-de="Installation" data-en="Installation"></div>
<h2 data-de="In drei Schritten produktiv" data-en="Up and running in three steps"></h2>
<p class="section-sub" data-de="Kein Docker, kein Linux, kein WSL. Ein MSI-Installer, der auf jedem aktuellen Windows läuft." data-en="No Docker, no Linux, no WSL. A single MSI installer that runs on any up-to-date Windows device."></p>
<div class="install-grid">
<div class="install-step">
<div class="step-num" data-de="Schritt 1" data-en="Step 1"></div>
<h3 data-de="MSI herunterladen" data-en="Download the MSI"></h3>
<p data-de="Nach dem Kauf erhältst Du sofort einen Download-Link für den Installer." data-en="After purchase, you immediately receive a download link for the installer."></p>
</div>
<div class="install-step">
<div class="step-num" data-de="Schritt 2" data-en="Step 2"></div>
<h3 data-de="Installieren & konfigurieren" data-en="Install & configure"></h3>
<p data-de="Benutzer- oder Maschinenkontext wählen. Installation dauert unter einer Minute." data-en="Choose user or machine context. Installation takes under a minute."></p>
</div>
<div class="install-step">
<div class="step-num" data-de="Schritt 3" data-en="Step 3"></div>
<h3 data-de="Datenquelle ablegen" data-en="Add your data source"></h3>
<p data-de="MBTiles, PMTiles oder COG in den vordefinierten Ordner kopieren — oder PostGIS verbinden. Dienst starten — fertig." data-en="Copy MBTiles, PMTiles, or COG files into the predefined folder — or connect PostGIS. Start the service — done."></p>
</div>
</div>
</section>
<hr class="divider">
<section id="pricing">
<div class="section-label" data-de="Preise" data-en="Pricing"></div>
<h2 data-de="Einmalig kaufen, dauerhaft nutzen" data-en="Buy once, use forever"></h2>
<p class="section-sub" data-de="Keine Abonnements, keine versteckten Gebühren. Alle zukünftigen Updates sind im Kaufpreis enthalten." data-en="No subscriptions, no hidden fees. All future updates are included in the purchase price."></p>
<div class="pricing">
<div class="price-card">
<div class="price-tag" data-de="Personal" data-en="Personal"></div>
<div class="price-name" data-de="Persönliche Lizenz" data-en="Personal license"></div>
<div class="price-desc" data-de="Für Einzelpersonen und private Projekte." data-en="For individuals and personal projects."></div>
<div class="price-amount" data-price-for="personal">€ 49</div>
<div class="price-note" data-de="inkl. anwendbarer Steuern" data-en="incl. applicable taxes"></div>
<ul class="price-features">
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Eine Installation" data-en="Single installation"></span></li>
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Lifetime Updates" data-en="Lifetime updates"></span></li>
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Sofort-Download nach Kauf" data-en="Instant download after purchase"></span></li>
</ul>
<a href="#" class="btn-secondary" data-paddle-checkout="personal" data-de="Jetzt kaufen" data-en="Buy now">Jetzt kaufen</a>
</div>
<div class="price-card featured">
<div class="price-tag" data-de="Organisation" data-en="Organisation"></div>
<div class="price-name" data-de="Organisationslizenz" data-en="Organisation license"></div>
<div class="price-desc" data-de="Für Unternehmen und Institutionen. Gilt für eine eigenständige Organisationseinheit." data-en="For companies and institutions. Valid for one independent organisational unit."></div>
<div class="price-amount" data-price-for="organisation">€ 999</div>
<div class="price-note" data-de="inkl. anwendbarer Steuern, einmalig" data-en="incl. applicable taxes, one-time"></div>
<ul class="price-features">
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Unbegrenzte Installationen innerhalb der Organisation" data-en="Unlimited installations within the organisation"></span></li>
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Lifetime Updates" data-en="Lifetime updates"></span></li>
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Automatisiertes Deployment (MSI/GPO)" data-en="Automated deployment (MSI/GPO)"></span></li>
<li><i class="ti ti-check" aria-hidden="true"></i><span data-de="Sofort-Download nach Kauf" data-en="Instant download after purchase"></span></li>
</ul>
<div class="support-hint" data-de="<strong>Optional:</strong> Support Contract für € 200/Jahr — priorisierte Bugfixes und direkter E-Mail-Support mit Antwort innerhalb von 2 Werktagen." data-en="<strong>Optional:</strong> Support contract for € 200/year — prioritised bug fixes and direct email support with a 2-business-day response time."></div>
<a href="#" class="btn-primary" data-paddle-checkout="organisation" data-de="Jetzt kaufen" data-en="Buy now">Jetzt kaufen</a>
</div>
</div>
</section>
<footer>
<p>© 2026 <a href="https://syncpoint.io">Syncpoint GmbH</a> · <a href="imprint.html" data-de="Impressum" data-en="Imprint">Impressum</a> · <a href="terms.html" data-de="Lizenzbedingungen" data-en="Terms & Conditions">Lizenzbedingungen</a> · <a href="refund.html" data-de="Erstattungsrichtlinie" data-en="Refund Policy">Erstattungsrichtlinie</a> · <a href="privacy.html" data-de="Datenschutz" data-en="Privacy">Datenschutz</a> · <a href="mailto:office@syncpoint.io">office@syncpoint.io</a></p>
</footer>
<script>
const heroTitles = {
de: 'Deine digitale Karte.<br><span>Auf Deinem Windows Gerät.</span>',
en: 'Your map data.<br><span>On your Windows device.</span>'
};
function setLang(lang) {
document.documentElement.lang = lang;
document.getElementById('hero-title').innerHTML = heroTitles[lang];
document.querySelectorAll('[data-de]').forEach(el => {
const t = el.getAttribute('data-' + lang);
if (!t || el.id === 'hero-title') return;
if (el.classList.contains('support-hint')) {
el.innerHTML = t.replace(/</g, '<').replace(/>/g, '>');
} else {
el.textContent = t;
}
});
document.getElementById('btn-de').classList.toggle('active', lang === 'de');
document.getElementById('btn-en').classList.toggle('active', lang === 'en');
localStorage.setItem('lang', lang);
}
const saved = localStorage.getItem('lang');
const browserLang = (navigator.language || 'en').toLowerCase().startsWith('de') ? 'de' : 'en';
setLang(saved || browserLang);
</script>
<!-- Paddle Billing: dynamische, lokalisierte Preise + Checkout -->
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
<script>
// === Konfiguration — hier Deine echten Werte aus dem Paddle-Dashboard eintragen ===
const PADDLE_CONFIG = {
// 'sandbox' zum Testen, 'production' für den Live-Betrieb
environment: 'production',
// Client-side Token (Paddle > Developer Tools > Authentication), beginnt mit test_ oder live_
token: 'live_34d2d6ff7ea531b18e6ec6dd7f9',
// Price-IDs der beiden Lizenzen (Paddle > Catalog > Products > Prices), beginnen mit pri_
prices: {
personal: 'pri_01kvapxk5m5wntf5a2hgc32ec0',
organisation: 'pri_01kvaqe5r4p2g7km9jmvzcs8y0'
},
// Welcher Betrag angezeigt wird: 'total' = inkl. Steuern, 'subtotal' = netto (z. B. für B2B)
priceField: 'total'
};
// Liste der angezeigten Tiers: data-Attribut -> Price-ID
const PADDLE_TIERS = [
{ key: 'personal', priceId: PADDLE_CONFIG.prices.personal },
{ key: 'organisation', priceId: PADDLE_CONFIG.prices.organisation }
];
function tokenValid() {
return /^(test|live)_/.test(PADDLE_CONFIG.token);
}
// Nur Tiers mit echter Price-ID werden dynamisch; der Rest behält den statischen Preis.
function validTiers() {
return PADDLE_TIERS.filter(t => /^pri_/.test(t.priceId));
}
function initPaddle() {
// Ohne gültigen Token oder ganz ohne konfigurierte Price-ID: statische Preise stehen lassen.
if (typeof Paddle === 'undefined' || !tokenValid() || validTiers().length === 0) return;
if (PADDLE_CONFIG.environment === 'sandbox') {
Paddle.Environment.set('sandbox');
}
Paddle.Initialize({ token: PADDLE_CONFIG.token });
loadPaddlePrices();
wirePaddleCheckout();
}
// Lokalisierte Preise laden (Währung/Steuer nach Standort des Besuchers, IP-basiert)
function loadPaddlePrices() {
const tiers = validTiers();
const items = tiers.map(t => ({ priceId: t.priceId, quantity: 1 }));
Paddle.PricePreview({ items })
.then(result => {
const currency = result.data.currencyCode;
result.data.details.lineItems.forEach(li => {
const tier = tiers.find(t => t.priceId === li.price.id);
if (!tier) return;
const amount = formatPrice(li, currency);
document.querySelectorAll('[data-price-for="' + tier.key + '"]')
.forEach(el => { el.textContent = amount; });
});
})
.catch(err => console.error('Paddle PricePreview fehlgeschlagen:', err));
}
// Preis lokalisiert formatieren, aber ohne Nachkommastellen bei ganzzahligen Beträgen.
// Rechnet aus dem Rohwert (kleinste Währungseinheit) statt am vorformatierten String zu schneiden.
function formatPrice(li, currency) {
const field = PADDLE_CONFIG.priceField === 'subtotal' ? 'subtotal' : 'total';
const locale = navigator.language || 'en';
let digits = 2;
try {
digits = new Intl.NumberFormat(locale, { style: 'currency', currency })
.resolvedOptions().maximumFractionDigits;
} catch (e) { /* unbekannte Währung -> Default 2 */ }
const major = Number(li.totals[field]) / Math.pow(10, digits);
try {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: currency,
// Ganzzahlig -> keine Nachkommastellen; krummer Betrag (z. B. durch Steuer) -> beibehalten
minimumFractionDigits: Number.isInteger(major) ? 0 : digits,
maximumFractionDigits: digits
}).format(major);
} catch (e) {
// Fallback: Paddles vorformatierten String nehmen und nur reine Null-Nachkommastellen entfernen
return li.formattedTotals[field].replace(/([.,])0+(?=\D*$)/, '');
}
}
// Kauf-Buttons mit dem Paddle-Checkout (Overlay) verbinden — nur für konfigurierte Tiers
function wirePaddleCheckout() {
const tiers = validTiers();
document.querySelectorAll('[data-paddle-checkout]').forEach(btn => {
const tier = tiers.find(t => t.key === btn.getAttribute('data-paddle-checkout'));
if (!tier) return;
btn.addEventListener('click', e => {
e.preventDefault();
Paddle.Checkout.open({ items: [{ priceId: tier.priceId, quantity: 1 }] });
});
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPaddle);
} else {
initPaddle();
}
</script>
</body>
</html>