Fix Scandinavian flyer layout by excluding CSS from DeepL translation.
Translate only visible body/title text, preserve HTML structure, and regenerate all flyer PDF/PNG exports. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+132
-132
@@ -5,46 +5,46 @@
|
||||
<title>Kapteins Daagbok - Beta-flyer</title>
|
||||
<style>
|
||||
@page {
|
||||
størrelse: A4 stående;
|
||||
size: A4 portrait;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
polstring: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
bredde: 210mm;
|
||||
højde: 297 mm;
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
farve: #e2e8f0;
|
||||
baggrund: #0f172a;
|
||||
color: #e2e8f0;
|
||||
background: #0f172a;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
|
||||
.side {
|
||||
bredde: 210mm;
|
||||
højde: 297mm;
|
||||
max-højde: 297mm;
|
||||
polstring: 12mm 15mm 10mm;
|
||||
.page {
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
max-height: 297mm;
|
||||
padding: 12mm 15mm 10mm;
|
||||
display: flex;
|
||||
flex-retning: kolonne;
|
||||
mellemrum: 5 mm;
|
||||
baggrund:
|
||||
radial-gradient(ellipse 120% 80% ved 100% 0%, rgba(56, 189, 248, 0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellipse 90% 60% ved 0% 100%, rgba(134, 59, 255, 0.14) 0%, transparent 50%),
|
||||
lineær-gradient(165deg, #0f172a 0%, #1e293b 45%, #0f172a 100%);
|
||||
flex-direction: column;
|
||||
gap: 5mm;
|
||||
background:
|
||||
radial-gradient(ellipse 120% 80% at 100% 0%, rgba(56, 189, 248, 0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellipse 90% 60% at 0% 100%, rgba(134, 59, 255, 0.14) 0%, transparent 50%),
|
||||
linear-gradient(165deg, #0f172a 0%, #1e293b 45%, #0f172a 100%);
|
||||
position: relative;
|
||||
overløb: skjult;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page::before {
|
||||
indhold: "";
|
||||
position: absolut;
|
||||
indsat: 8 mm;
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 8mm;
|
||||
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||
border-radius: 4mm;
|
||||
pointer-events: none;
|
||||
@@ -53,247 +53,247 @@
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
mellemrum: 5mm;
|
||||
flex-krympning: 0;
|
||||
position: relativ;
|
||||
gap: 5mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.logo {
|
||||
bredde: 16mm;
|
||||
højde: 16mm;
|
||||
flex-krymp: 0;
|
||||
width: 16mm;
|
||||
height: 16mm;
|
||||
flex-shrink: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.title-block h1 {
|
||||
skriftstørrelse: 23pt;
|
||||
font-vægt: 700;
|
||||
font-size: 23pt;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
farve: #f8fafc;
|
||||
linjehøjde: 1.1;
|
||||
color: #f8fafc;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.title-block p {
|
||||
skriftstørrelse: 12pt;
|
||||
farve: #94a3b8;
|
||||
margin-top: 1,5 mm;
|
||||
font-size: 12pt;
|
||||
color: #94a3b8;
|
||||
margin-top: 1.5mm;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-left: auto;
|
||||
align-self: flex-start;
|
||||
baggrund: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
farve: #1e293b;
|
||||
skriftstørrelse: 11pt;
|
||||
font-vægt: 800;
|
||||
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
color: #1e293b;
|
||||
font-size: 11pt;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
polstring: 2,5 mm 4,5 mm;
|
||||
padding: 2.5mm 4.5mm;
|
||||
border-radius: 2mm;
|
||||
tekst-transformation: store bogstaver;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.intro {
|
||||
skriftstørrelse: 12pt;
|
||||
linjehøjde: 1,5;
|
||||
farve: #cbd5e1;
|
||||
font-size: 12pt;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
flex-shrink: 0;
|
||||
max-bredde: 95%;
|
||||
position: relativ;
|
||||
max-width: 95%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.intro strong {
|
||||
farve: #f8fafc;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.screenshots {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
mellemrum: 3 mm;
|
||||
gap: 3mm;
|
||||
flex-shrink: 0;
|
||||
position: relativ;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.screenshot-kort {
|
||||
border-radius: 2,5 mm;
|
||||
overløb: skjult;
|
||||
.screenshot-card {
|
||||
border-radius: 2.5mm;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
baggrund: rgba(15, 23, 42, 0.55);
|
||||
background: rgba(15, 23, 42, 0.55);
|
||||
display: flex;
|
||||
flex-retning: kolonne;
|
||||
min-bredde: 0;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.screenshot-kort img {
|
||||
bredde: 100%;
|
||||
højde: 50mm;
|
||||
.screenshot-card img {
|
||||
width: 100%;
|
||||
height: 50mm;
|
||||
object-fit: contain;
|
||||
object-position: top center;
|
||||
display: block;
|
||||
baggrund: #0b1220;
|
||||
background: #0b1220;
|
||||
}
|
||||
|
||||
.screenshot-caption {
|
||||
skriftstørrelse: 9pt;
|
||||
farve: #94a3b8;
|
||||
tekstjustering: center;
|
||||
polstring: 1,5 mm 2 mm;
|
||||
linjehøjde: 1,3;
|
||||
font-size: 9pt;
|
||||
color: #94a3b8;
|
||||
text-align: center;
|
||||
padding: 1.5mm 2mm;
|
||||
line-height: 1.3;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.funktioner {
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-kolonner: 1fr 1fr;
|
||||
mellemrum: 1,8 mm 6 mm;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.8mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relativ;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.feature {
|
||||
display: flex;
|
||||
mellemrum: 2,5 mm;
|
||||
gap: 2.5mm;
|
||||
align-items: flex-start;
|
||||
skriftstørrelse: 10.5pt;
|
||||
linjehøjde: 1,28;
|
||||
farve: #e2e8f0;
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.28;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
farve: #38bdf8;
|
||||
font-vægt: 700;
|
||||
flex-krymp: 0;
|
||||
bredde: 4mm;
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
width: 4mm;
|
||||
}
|
||||
|
||||
.lang-liste {
|
||||
.lang-list {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
mellemrum: 1,5 mm;
|
||||
gap: 1.5mm;
|
||||
}
|
||||
|
||||
.lang-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
mellemrum: 1,2 mm;
|
||||
gap: 1.2mm;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.feature-flag {
|
||||
display: inline-block;
|
||||
bredde: 5 mm;
|
||||
højde: 3,5 mm;
|
||||
border-radius: 0,3 mm;
|
||||
width: 5mm;
|
||||
height: 3.5mm;
|
||||
border-radius: 0.3mm;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 0 0 0.15mm rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.lang-sep {
|
||||
farve: #94a3b8;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.beta-box {
|
||||
baggrund: rgba(30, 41, 59, 0.85);
|
||||
background: rgba(30, 41, 59, 0.85);
|
||||
border: 1px solid rgba(251, 191, 36, 0.35);
|
||||
border-left: 3px solid #fbbf24;
|
||||
border-radius: 3mm;
|
||||
polstring: 5mm 6mm;
|
||||
padding: 5mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relativ;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.beta-box h2 {
|
||||
skriftstørrelse: 12,5pt;
|
||||
farve: #fbbf24;
|
||||
margin-bund: 2mm;
|
||||
font-vægt: 700;
|
||||
font-size: 12.5pt;
|
||||
color: #fbbf24;
|
||||
margin-bottom: 2mm;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.beta-box p {
|
||||
skriftstørrelse: 10,5pt;
|
||||
linjehøjde: 1,5;
|
||||
farve: #cbd5e1;
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.cta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
mellemrum: 7mm;
|
||||
baggrund: rgba(15, 23, 42, 0.6);
|
||||
gap: 7mm;
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
border: 1px solid rgba(148, 163, 184, 0.2);
|
||||
border-radius: 4mm;
|
||||
polstring: 5 mm 6 mm;
|
||||
padding: 5mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.qr {
|
||||
bredde: 32mm;
|
||||
højde: 32mm;
|
||||
baggrund: #fff;
|
||||
polstring: 2 mm;
|
||||
border-radius: 2 mm;
|
||||
width: 32mm;
|
||||
height: 32mm;
|
||||
background: #fff;
|
||||
padding: 2mm;
|
||||
border-radius: 2mm;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qr img {
|
||||
width: 100%;
|
||||
højde: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cta-tekst h3 {
|
||||
skriftstørrelse: 14,5pt;
|
||||
farve: #38bdf8;
|
||||
font-vægt: 700;
|
||||
margin-bund: 2mm;
|
||||
.cta-text h3 {
|
||||
font-size: 14.5pt;
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
|
||||
.cta-text p {
|
||||
skriftstørrelse: 11pt;
|
||||
farve: #94a3b8;
|
||||
linjehøjde: 1,5;
|
||||
font-size: 11pt;
|
||||
color: #94a3b8;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
mellemrum: 2mm;
|
||||
gap: 2mm;
|
||||
margin-top: 3mm;
|
||||
}
|
||||
|
||||
.tag {
|
||||
skriftstørrelse: 9,5pt;
|
||||
font-vægt: 600;
|
||||
font-size: 9.5pt;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
tekst-transformation: store bogstaver;
|
||||
farve: #64748b;
|
||||
text-transform: uppercase;
|
||||
color: #64748b;
|
||||
border: 1px solid rgba(100, 116, 139, 0.4);
|
||||
border-radius: 1,5 mm;
|
||||
polstring: 1 mm 2,5 mm;
|
||||
border-radius: 1.5mm;
|
||||
padding: 1mm 2.5mm;
|
||||
}
|
||||
|
||||
sidefod {
|
||||
footer {
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.15);
|
||||
padding-top: 3mm;
|
||||
margin-top: auto;
|
||||
flex-shrink: 0;
|
||||
skriftstørrelse: 9,5pt;
|
||||
linjehøjde: 1,5;
|
||||
farve: #64748b;
|
||||
position: relativ;
|
||||
font-size: 9.5pt;
|
||||
line-height: 1.5;
|
||||
color: #64748b;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
sidefod strong {
|
||||
farve: #94a3b8;
|
||||
font-vægt: 600;
|
||||
footer strong {
|
||||
color: #94a3b8;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -314,7 +314,7 @@
|
||||
<strong>også offline</strong> kan bruges til søs.
|
||||
</p>
|
||||
|
||||
<section class="features" aria-label="Funktionen">
|
||||
<section class="features" aria-label="Funktioner">
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Rejsedage i nautisk logbogsformat (havn, vejr, sejl, besætning, brændstofniveauer)</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Offline-kompatibel PWA - kører på enhver smartphone og tablet</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Simpelt login uden adgangskode Passkey.</span></div>
|
||||
@@ -328,22 +328,22 @@
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Krypteret sikkerhedskopiering og gendannelse</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Del logbog med venner</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Et vilkårligt antal skibe og logbøger</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="37" height="28" fill="#C8102E"/><rect x="12" width="4" height="28" fill="#fff"/><rect y="12" width="37" height="4" fill="#fff"/></svg>Dansk</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>Engelsk</span></span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>English</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="37" height="28" fill="#C8102E"/><rect x="12" width="4" height="28" fill="#fff"/><rect y="12" width="37" height="4" fill="#fff"/></svg>Dansk</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 16 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="16" height="10" fill="#006AA7"/><rect x="5" width="2" height="10" fill="#FECC00"/><rect y="4" width="16" height="2" fill="#FECC00"/></svg>Svenska</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="22" height="16" fill="#BA0C2F"/><rect x="6" width="4" height="16" fill="#fff"/><rect y="6" width="22" height="4" fill="#fff"/><rect x="7" width="2" height="16" fill="#00205B"/><rect y="7" width="22" height="2" fill="#00205B"/></svg>Norsk</span></span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>3 temaer, hver med en lys og en mørk variant</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Fremstillet i Kiel.Sailing.City..</span></div>
|
||||
</section>
|
||||
|
||||
<section class="screenshots" aria-label="App-Screenshots">
|
||||
<section class="screenshots" aria-label="Skærmbilleder af appen">
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-login.png" alt="Anmeldung mit Passkey und Demo" />
|
||||
<img src="assets/screenshot-login.png" alt="Registrering med Passkey og demo" />
|
||||
<figcaption class="screenshot-caption">Registrering & Passkey</figcaption>
|
||||
</figure>
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-logbook.png" alt="Logbuch-Journal mit Reisetagen" />
|
||||
<img src="assets/screenshot-logbook.png" alt="Logbogsdagbog med rejsedage" />
|
||||
<figcaption class="screenshot-caption">Logbogsdagbog</figcaption>
|
||||
</figure>
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-vessel.png" alt="Schiffs-Stammdaten mit Yachtfoto" />
|
||||
<img src="assets/screenshot-vessel.png" alt="Skibsdata med foto af yacht" />
|
||||
<figcaption class="screenshot-caption">Skibsdata</figcaption>
|
||||
</figure>
|
||||
</section>
|
||||
@@ -359,7 +359,7 @@
|
||||
|
||||
<section class="cta">
|
||||
<div class="qr">
|
||||
<img src="assets/qr-kapteins-daagbok.eu.png" alt="QR-Code: kapteins-daagbok.eu" />
|
||||
<img src="assets/qr-kapteins-daagbok.eu.png" alt="QR-kode: kapteins-daagbok.eu" />
|
||||
</div>
|
||||
<div class="cta-text">
|
||||
<h3>kapteins-daagbok.eu</h3>
|
||||
@@ -374,7 +374,7 @@
|
||||
|
||||
<footer>
|
||||
<strong>Påtryk</strong><br />
|
||||
KnorrLabs - Markus F.J. Busche - Knorrstr. 16 · 24106 Kiel - elpatron+kd@mailbox.org.
|
||||
KnorrLabs · Markus F.J. Busche · Knorrstr. 16 · 24106 Kiel · elpatron+kd@mailbox.org
|
||||
</footer>
|
||||
</article>
|
||||
</body>
|
||||
|
||||
+135
-135
@@ -5,45 +5,45 @@
|
||||
<title>Kapteins Daagbok - Beta-flygeblad</title>
|
||||
<style>
|
||||
@page {
|
||||
størrelse: A4 stående;
|
||||
size: A4 portrait;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
polstring: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
bredde: 210mm;
|
||||
høyde: 297 mm;
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
farge: #e2e8f0;
|
||||
bakgrunn: #0f172a;
|
||||
color: #e2e8f0;
|
||||
background: #0f172a;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
|
||||
.page {
|
||||
bredde: 210mm;
|
||||
høyde: 297mm;
|
||||
max-høyde: 297mm;
|
||||
polstring: 12mm 15mm 10mm;
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
max-height: 297mm;
|
||||
padding: 12mm 15mm 10mm;
|
||||
display: flex;
|
||||
flex-retning: kolonne;
|
||||
mellomrom: 5 mm
|
||||
bakgrunn:
|
||||
radial-gradient(ellipse 120% 80% ved 100% 0%, rgba(56, 189, 248, 0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellipse 90% 60% på 0% 100%, rgba(134, 59, 255, 0.14) 0%, gjennomsiktig 50%),
|
||||
lineær-gradient(165deg, #0f172a 0%, #1e293b 45%, #0f172a 100%);
|
||||
posisjon: relativ;
|
||||
overflow: skjult;
|
||||
flex-direction: column;
|
||||
gap: 5mm;
|
||||
background:
|
||||
radial-gradient(ellipse 120% 80% at 100% 0%, rgba(56, 189, 248, 0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellipse 90% 60% at 0% 100%, rgba(134, 59, 255, 0.14) 0%, transparent 50%),
|
||||
linear-gradient(165deg, #0f172a 0%, #1e293b 45%, #0f172a 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page::before {
|
||||
innhold: "";
|
||||
posisjon: absolutt
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 8mm;
|
||||
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||
border-radius: 4mm;
|
||||
@@ -53,246 +53,246 @@
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
mellomrom: 5 mm
|
||||
flex-krymp: 0;
|
||||
posisjon: relativ;
|
||||
gap: 5mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.logo {
|
||||
bredde: 16mm;
|
||||
høyde: 16mm;
|
||||
flex-krymp: 0;
|
||||
width: 16mm;
|
||||
height: 16mm;
|
||||
flex-shrink: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.title-block h1 {
|
||||
skriftstørrelse: 23pt;
|
||||
font-size: 23pt;
|
||||
font-weight: 700;
|
||||
bokstavavstand: -0.02em;
|
||||
farge: #f8fafc;
|
||||
linjehøyde: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
color: #f8fafc;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.title-block p {
|
||||
skriftstørrelse: 12pt;
|
||||
farge: #94a3b8;
|
||||
margin-topp: 1,5 mm;
|
||||
font-size: 12pt;
|
||||
color: #94a3b8;
|
||||
margin-top: 1.5mm;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-left: auto;
|
||||
align-self: flex-start;
|
||||
bakgrunn: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
farge: #1e293b;
|
||||
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
color: #1e293b;
|
||||
font-size: 11pt;
|
||||
font-weight: 800;
|
||||
bokstavavstand: 0,12em;
|
||||
polstring: 2,5 mm 4,5 mm;
|
||||
letter-spacing: 0.12em;
|
||||
padding: 2.5mm 4.5mm;
|
||||
border-radius: 2mm;
|
||||
tekst-transformasjon: versaler;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.intro {
|
||||
skriftstørrelse: 12pt;
|
||||
linjehøyde: 1,5
|
||||
farge: #cbd5e1;
|
||||
flex-krymp: 0;
|
||||
font-size: 12pt;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
flex-shrink: 0;
|
||||
max-width: 95%;
|
||||
posisjon: relativ;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.intro strong {
|
||||
farge: #f8fafc;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.skjermbilder {
|
||||
.screenshots {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
mellomrom: 3 mm
|
||||
flex-krymp: 0;
|
||||
posisjon: relativ;
|
||||
gap: 3mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.skjermbilde-kort {
|
||||
border-radius: 2,5 mm;
|
||||
overflow: skjult;
|
||||
.screenshot-card {
|
||||
border-radius: 2.5mm;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
bakgrunn: rgba(15, 23, 42, 0.55);
|
||||
background: rgba(15, 23, 42, 0.55);
|
||||
display: flex;
|
||||
flex-retning: kolonne;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.screenshot-card img {
|
||||
bredde: 100 %;
|
||||
høyde: 50mm;
|
||||
width: 100%;
|
||||
height: 50mm;
|
||||
object-fit: contain;
|
||||
objekt-posisjon: øverst i midten;
|
||||
object-position: top center;
|
||||
display: block;
|
||||
bakgrunn: #0b1220;
|
||||
background: #0b1220;
|
||||
}
|
||||
|
||||
.screenshot-caption {
|
||||
font-size: 9pt;
|
||||
farge: #94a3b8;
|
||||
tekstjustering: midt;
|
||||
polstring: 1.5mm 2mm;
|
||||
linjehøyde: 1.3
|
||||
flex-krymping: 0;
|
||||
color: #94a3b8;
|
||||
text-align: center;
|
||||
padding: 1.5mm 2mm;
|
||||
line-height: 1.3;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-kolonner: 1fr 1fr;
|
||||
gap: 1,8 mm 6 mm
|
||||
flex-krymp: 0;
|
||||
posisjon: relativ;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.8mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.feature {
|
||||
display: flex;
|
||||
mellomrom: 2,5 mm;
|
||||
gap: 2.5mm;
|
||||
align-items: flex-start;
|
||||
font-size: 10.5pt;
|
||||
linjehøyde: 1,28
|
||||
farge: #e2e8f0;
|
||||
line-height: 1.28;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
farge: #38bdf8;
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
flex-krymp: 0;
|
||||
bredde: 4mm;
|
||||
flex-shrink: 0;
|
||||
width: 4mm;
|
||||
}
|
||||
|
||||
.lang-list {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
mellomrom: 1,5 mm;
|
||||
gap: 1.5mm;
|
||||
}
|
||||
|
||||
.lang-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
mellomrom: 1,2 mm;
|
||||
gap: 1.2mm;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.feature-flag {
|
||||
display: inline-block;
|
||||
bredde: 5 mm;
|
||||
høyde: 3,5 mm;
|
||||
border-radius: 0,3 mm
|
||||
flex-krymping: 0;
|
||||
box-shadow: 0 0 0 0 0,15mm rgba(0, 0, 0, 0, 0,25);
|
||||
width: 5mm;
|
||||
height: 3.5mm;
|
||||
border-radius: 0.3mm;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 0 0 0.15mm rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.lang-sep {
|
||||
farge: #94a3b8;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.beta-box {
|
||||
bakgrunn: rgba(30, 41, 59, 0.85);
|
||||
background: rgba(30, 41, 59, 0.85);
|
||||
border: 1px solid rgba(251, 191, 36, 0.35);
|
||||
border-left: 3px solid #fbbf24;
|
||||
border-radius: 3mm;
|
||||
polstring: 5mm 6mm
|
||||
flex-krymp: 0;
|
||||
posisjon: relativ;
|
||||
padding: 5mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.beta-box h2 {
|
||||
skriftstørrelse: 12,5pt;
|
||||
farge: #fbbf24;
|
||||
margin-bunn: 2 mm
|
||||
font-size: 12.5pt;
|
||||
color: #fbbf24;
|
||||
margin-bottom: 2mm;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.beta-box p {
|
||||
skriftstørrelse: 10,5pt;
|
||||
linjehøyde: 1,5
|
||||
farge: #cbd5e1;
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.cta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
mellomrom: 7mm;
|
||||
bakgrunn: rgba(15, 23, 42, 0.6);
|
||||
gap: 7mm;
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
border: 1px solid rgba(148, 163, 184, 0.2);
|
||||
border-radius: 4mm;
|
||||
polstring: 5 mm 6 mm
|
||||
flex-krymp: 0;
|
||||
posisjon: relativ;
|
||||
padding: 5mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.qr {
|
||||
bredde: 32mm;
|
||||
høyde: 32mm;
|
||||
bakgrunn: #fff;
|
||||
polstring: 2mm;
|
||||
width: 32mm;
|
||||
height: 32mm;
|
||||
background: #fff;
|
||||
padding: 2mm;
|
||||
border-radius: 2mm;
|
||||
flex-krymp: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qr img {
|
||||
bredde: 100 %;
|
||||
høyde: 100 %;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cta-text h3 {
|
||||
skriftstørrelse: 14,5pt;
|
||||
farge: #38bdf8;
|
||||
font-vekt: 700
|
||||
margin-bunn: 2mm;
|
||||
font-size: 14.5pt;
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
|
||||
.cta-text p {
|
||||
skriftstørrelse: 11pt;
|
||||
farge: #94a3b8;
|
||||
linjehøyde: 1,5;
|
||||
font-size: 11pt;
|
||||
color: #94a3b8;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
mellomrom: 2mm;
|
||||
gap: 2mm;
|
||||
margin-top: 3mm;
|
||||
}
|
||||
|
||||
.tag {
|
||||
skriftstørrelse: 9,5pt;
|
||||
font-size: 9.5pt;
|
||||
font-weight: 600;
|
||||
bokstavavstand: 0.04em;
|
||||
tekst-transformasjon: store bokstaver;
|
||||
farge: #64748b;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: #64748b;
|
||||
border: 1px solid rgba(100, 116, 139, 0.4);
|
||||
border-radius: 1,5 mm
|
||||
polstring: 1 mm 2,5 mm;
|
||||
border-radius: 1.5mm;
|
||||
padding: 1mm 2.5mm;
|
||||
}
|
||||
|
||||
bunntekst {
|
||||
footer {
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.15);
|
||||
padding-top: 3mm;
|
||||
margin-topp: auto;
|
||||
flex-krymp: 0;
|
||||
skriftstørrelse: 9,5pt;
|
||||
linjehøyde: 1,5
|
||||
farge: #64748b;
|
||||
posisjon: relativ;
|
||||
margin-top: auto;
|
||||
flex-shrink: 0;
|
||||
font-size: 9.5pt;
|
||||
line-height: 1.5;
|
||||
color: #64748b;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
bunntekst strong {
|
||||
farge: #94a3b8;
|
||||
footer strong {
|
||||
color: #94a3b8;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -309,12 +309,12 @@
|
||||
</header>
|
||||
|
||||
<p class="intro">
|
||||
Før loggboken om bord digitalt: reisedager, GPS-spor, mannskaps- og skipsdata
|
||||
Oppbevar loggboken om bord digitalt: reisedager, GPS-spor, mannskaps- og skipsdata
|
||||
<strong>Ende-til-ende-kryptert</strong>kan installeres som en app og
|
||||
<strong>også offline</strong> kan brukes til sjøs.
|
||||
</p>
|
||||
|
||||
<section class="features" aria-label="Funktionen">
|
||||
<section class="features" aria-label="Funksjoner">
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Reisedager i nautisk loggbokformat (havn, vær, seil, mannskap, drivstoffnivå)</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Offline-kompatibel PWA - kjører på alle smarttelefoner og nettbrett</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Enkel passordfri Passkey-pålogging</span></div>
|
||||
@@ -328,22 +328,22 @@
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Kryptert sikkerhetskopiering og gjenoppretting</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Del loggboken med venner</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Et hvilket som helst antall skip og loggbøker</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="22" height="16" fill="#BA0C2F"/><rect x="6" width="4" height="16" fill="#fff"/><rect y="6" width="22" height="4" fill="#fff"/><rect x="7" width="2" height="16" fill="#00205B"/><rect y="7" width="22" height="2" fill="#00205B"/></svg>Norsk</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>Engelsk</span></span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>English</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="37" height="28" fill="#C8102E"/><rect x="12" width="4" height="28" fill="#fff"/><rect y="12" width="37" height="4" fill="#fff"/></svg>Dansk</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 16 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="16" height="10" fill="#006AA7"/><rect x="5" width="2" height="10" fill="#FECC00"/><rect y="4" width="16" height="2" fill="#FECC00"/></svg>Svenska</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="22" height="16" fill="#BA0C2F"/><rect x="6" width="4" height="16" fill="#fff"/><rect y="6" width="22" height="4" fill="#fff"/><rect x="7" width="2" height="16" fill="#00205B"/><rect y="7" width="22" height="2" fill="#00205B"/></svg>Norsk</span></span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>3 temaer, hvert med en lys og en mørk variant</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Laget i Kiel.Sailing.City..</span></div>
|
||||
</section>
|
||||
|
||||
<section class="screenshots" aria-label="App-Screenshots">
|
||||
<section class="screenshots" aria-label="Skjermbilder av appen">
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-login.png" alt="Anmeldung mit Passkey und Demo" />
|
||||
<img src="assets/screenshot-login.png" alt="Registrering med Passkey og demo" />
|
||||
<figcaption class="screenshot-caption">Registrering & Passkey</figcaption>
|
||||
</figure>
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-logbook.png" alt="Logbuch-Journal mit Reisetagen" />
|
||||
<img src="assets/screenshot-logbook.png" alt="Loggbok med reisedager" />
|
||||
<figcaption class="screenshot-caption">Loggbokdagbok</figcaption>
|
||||
</figure>
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-vessel.png" alt="Schiffs-Stammdaten mit Yachtfoto" />
|
||||
<img src="assets/screenshot-vessel.png" alt="Skipsdata med bilde av båten" />
|
||||
<figcaption class="screenshot-caption">Skipsdata</figcaption>
|
||||
</figure>
|
||||
</section>
|
||||
@@ -359,14 +359,14 @@
|
||||
|
||||
<section class="cta">
|
||||
<div class="qr">
|
||||
<img src="assets/qr-kapteins-daagbok.eu.png" alt="QR-Code: kapteins-daagbok.eu" />
|
||||
<img src="assets/qr-kapteins-daagbok.eu.png" alt="QR-kode: kapteins-daagbok.eu" />
|
||||
</div>
|
||||
<div class="cta-text">
|
||||
<h3>kapteins-daagbok.eu</h3>
|
||||
<p>Åpne i nettleseren eller legg til som en app på startskjermen. Registrer deg med Passkey - ingen appbutikk er nødvendig.</p>
|
||||
<div class="tags">
|
||||
<span class="tag">Kostnadsfritt</span>
|
||||
<span class="tag">Reklame gratis</span>
|
||||
<span class="tag">Gratis annonsering</span>
|
||||
<span class="tag">E2E-kryptert</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -374,7 +374,7 @@
|
||||
|
||||
<footer>
|
||||
<strong>Avtrykk</strong><br />
|
||||
KnorrLabs - Markus F.J. Busche - Knorrstr. 16 · 24106 Kiel - elpatron+kd@mailbox.org - Knorrstr. 16 · 24106 Kiel - elpatron+kd@mailbox.org
|
||||
KnorrLabs · Markus F.J. Busche · Knorrstr. 16 · 24106 Kiel · elpatron+kd@mailbox.org
|
||||
</footer>
|
||||
</article>
|
||||
</body>
|
||||
|
||||
+178
-178
@@ -5,295 +5,295 @@
|
||||
<title>Kapteins Daagbok - Beta-flygblad</title>
|
||||
<style>
|
||||
@page {
|
||||
storlek: A4 stående;
|
||||
marginal: 0;
|
||||
size: A4 portrait;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
box-storlek: border-box;
|
||||
marginal: 0;
|
||||
stoppning: 0;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, kropp {
|
||||
bredd: 210 mm;
|
||||
höjd: 297 mm;
|
||||
html, body {
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
||||
färg: #e2e8f0;
|
||||
bakgrund: #0f172a;
|
||||
-webkit-print-color-adjust: exakt;
|
||||
justering av utskriftsfärg: exakt;
|
||||
color: #e2e8f0;
|
||||
background: #0f172a;
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
|
||||
.sida {
|
||||
bredd: 210 mm;
|
||||
höjd: 297 mm;
|
||||
max-höjd: 297 mm;
|
||||
stoppning: 12mm 15mm 10mm;
|
||||
.page {
|
||||
width: 210mm;
|
||||
height: 297mm;
|
||||
max-height: 297mm;
|
||||
padding: 12mm 15mm 10mm;
|
||||
display: flex;
|
||||
flex-riktning: kolumn;
|
||||
mellanrum: 5mm;
|
||||
bakgrund:
|
||||
radial-gradient(ellips 120% 80% vid 100% 0%, rgba(56, 189, 248, 0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellips 90% 60% på 0% 100%, rgba(134, 59, 255, 0.14) 0%, transparent 50%),
|
||||
linjär-gradient(165deg, #0f172a 0%, #1e293b 45%, #0f172a 100%);
|
||||
position: relativ;
|
||||
överflöd: dold;
|
||||
flex-direction: column;
|
||||
gap: 5mm;
|
||||
background:
|
||||
radial-gradient(ellipse 120% 80% at 100% 0%, rgba(56, 189, 248, 0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellipse 90% 60% at 0% 100%, rgba(134, 59, 255, 0.14) 0%, transparent 50%),
|
||||
linear-gradient(165deg, #0f172a 0%, #1e293b 45%, #0f172a 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page::before {
|
||||
innehåll: "";
|
||||
position: absolut;
|
||||
inskjutet: 8mm;
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 8mm;
|
||||
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||
gränsradie: 4mm;
|
||||
pekare-händelser: ingen;
|
||||
border-radius: 4mm;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
sidhuvud {
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
mellanrum: 5mm;
|
||||
flex-krympning: 0;
|
||||
position: relativ;
|
||||
gap: 5mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.logo {
|
||||
bredd: 16mm;
|
||||
höjd: 16 mm;
|
||||
flex-krympning: 0;
|
||||
objektanpassning: innehålla;
|
||||
width: 16mm;
|
||||
height: 16mm;
|
||||
flex-shrink: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.title-block h1 {
|
||||
teckenstorlek: 23pt;
|
||||
typsnittsvikt: 700;
|
||||
bokstavsavstånd: -0,02em;
|
||||
färg: #f8fafc;
|
||||
Linjehöjd: 1.1;
|
||||
font-size: 23pt;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
color: #f8fafc;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.title-block p {
|
||||
teckenstorlek: 12pt;
|
||||
färg: #94a3b8;
|
||||
marginal-topp: 1,5 mm;
|
||||
font-size: 12pt;
|
||||
color: #94a3b8;
|
||||
margin-top: 1.5mm;
|
||||
}
|
||||
|
||||
.badge {
|
||||
marginal-vänster: auto;
|
||||
margin-left: auto;
|
||||
align-self: flex-start;
|
||||
bakgrund: linjär-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
färg: #1e293b;
|
||||
font-storlek: 11pt;
|
||||
typsnittsvikt: 800;
|
||||
bokstavsavstånd: 0.12em;
|
||||
stoppning: 2,5 mm 4,5 mm;
|
||||
gränsradie: 2mm;
|
||||
text-transform: versaler;
|
||||
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
color: #1e293b;
|
||||
font-size: 11pt;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
padding: 2.5mm 4.5mm;
|
||||
border-radius: 2mm;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.intro {
|
||||
teckenstorlek: 12pt;
|
||||
radhöjd: 1,5;
|
||||
färg: #cbd5e1;
|
||||
flex-krympning: 0;
|
||||
max-bredd: 95%;
|
||||
position: relativ;
|
||||
font-size: 12pt;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
flex-shrink: 0;
|
||||
max-width: 95%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.intro strong {
|
||||
färg: #f8fafc;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.skärmdumpar {
|
||||
display: rutnät;
|
||||
grid-template-kolumner: repeat(3, 1fr);
|
||||
mellanrum: 3mm;
|
||||
flex-krympning: 0;
|
||||
position: relativ;
|
||||
.screenshots {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 3mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.skärmdump-kort {
|
||||
gränsradie: 2,5 mm;
|
||||
överflöde: dold;
|
||||
kant: 1px solid rgba(148, 163, 184, 0.22);
|
||||
bakgrund: rgba(15, 23, 42, 0.55);
|
||||
.screenshot-card {
|
||||
border-radius: 2.5mm;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
background: rgba(15, 23, 42, 0.55);
|
||||
display: flex;
|
||||
flex-riktning: kolumn;
|
||||
min-bredd: 0;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.skärmdumpskort img {
|
||||
bredd: 100%;
|
||||
höjd: 50mm;
|
||||
objektanpassning: innehålla;
|
||||
objekt-position: övre mitten;
|
||||
.screenshot-card img {
|
||||
width: 100%;
|
||||
height: 50mm;
|
||||
object-fit: contain;
|
||||
object-position: top center;
|
||||
display: block;
|
||||
bakgrund: #0b1220;
|
||||
background: #0b1220;
|
||||
}
|
||||
|
||||
.skärmdump-bildtext {
|
||||
teckenstorlek: 9pt;
|
||||
färg: #94a3b8;
|
||||
.screenshot-caption {
|
||||
font-size: 9pt;
|
||||
color: #94a3b8;
|
||||
text-align: center;
|
||||
stoppning: 1,5 mm 2 mm;
|
||||
Linjehöjd: 1,3;
|
||||
flex-krympning: 0;
|
||||
padding: 1.5mm 2mm;
|
||||
line-height: 1.3;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.funktioner {
|
||||
display: rutnät;
|
||||
grid-template-kolumner: 1fr 1fr;
|
||||
mellanrum: 1,8mm 6mm;
|
||||
flex-krympning: 0;
|
||||
position: relativ;
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.8mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.feature {
|
||||
display: flex;
|
||||
mellanrum: 2,5 mm;
|
||||
linje-objekt: flex-start;
|
||||
teckenstorlek: 10,5pt;
|
||||
radhöjd: 1,28;
|
||||
färg: #e2e8f0;
|
||||
gap: 2.5mm;
|
||||
align-items: flex-start;
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.28;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.feature-ikon {
|
||||
färg: #38bdf8;
|
||||
typsnittsvikt: 700;
|
||||
flex-krympning: 0;
|
||||
bredd: 4 mm;
|
||||
.feature-icon {
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
width: 4mm;
|
||||
}
|
||||
|
||||
.lang-lista {
|
||||
.lang-list {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
linje-punkter: mitt;
|
||||
mellanrum: 1,5 mm;
|
||||
align-items: center;
|
||||
gap: 1.5mm;
|
||||
}
|
||||
|
||||
.lang-objekt {
|
||||
.lang-item {
|
||||
display: inline-flex;
|
||||
anpassa objekt: mitt;
|
||||
mellanrum: 1,2 mm;
|
||||
align-items: center;
|
||||
gap: 1.2mm;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.feature-flag {
|
||||
display: inline-block;
|
||||
bredd: 5mm;
|
||||
höjd: 3,5 mm;
|
||||
gränsradie: 0,3 mm;
|
||||
flex-krympning: 0;
|
||||
box-shadow: 0 0 0 0,15mm rgba(0, 0, 0, 0, 0,25);
|
||||
width: 5mm;
|
||||
height: 3.5mm;
|
||||
border-radius: 0.3mm;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 0 0 0.15mm rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.lang-sep {
|
||||
färg: #94a3b8;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.beta-box {
|
||||
bakgrund: rgba(30, 41, 59, 0,85);
|
||||
background: rgba(30, 41, 59, 0.85);
|
||||
border: 1px solid rgba(251, 191, 36, 0.35);
|
||||
gräns-vänster: 3px solid #fbbf24;
|
||||
gränsradie: 3mm;
|
||||
stoppning: 5mm 6mm;
|
||||
flex-krympning: 0;
|
||||
position: relativ;
|
||||
border-left: 3px solid #fbbf24;
|
||||
border-radius: 3mm;
|
||||
padding: 5mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.beta-box h2 {
|
||||
teckenstorlek: 12,5pt;
|
||||
färg: #fbbf24;
|
||||
marginal-botten: 2mm;
|
||||
typsnittsvikt: 700;
|
||||
font-size: 12.5pt;
|
||||
color: #fbbf24;
|
||||
margin-bottom: 2mm;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.beta-box p {
|
||||
teckenstorlek: 10,5pt;
|
||||
Linjehöjd: 1,5;
|
||||
färg: #cbd5e1;
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.cta {
|
||||
display: flex;
|
||||
justera-objekt: mitt;
|
||||
mellanrum: 7mm;
|
||||
bakgrund: rgba(15, 23, 42, 0.6);
|
||||
align-items: center;
|
||||
gap: 7mm;
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
border: 1px solid rgba(148, 163, 184, 0.2);
|
||||
gränsradie: 4mm;
|
||||
stoppning: 5mm 6mm;
|
||||
flex-krympning: 0;
|
||||
position: relativ;
|
||||
border-radius: 4mm;
|
||||
padding: 5mm 6mm;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.qr {
|
||||
bredd: 32mm;
|
||||
höjd: 32 mm;
|
||||
bakgrund: #fff;
|
||||
stoppning: 2mm;
|
||||
gräns-radie: 2mm;
|
||||
flex-krympning: 0;
|
||||
width: 32mm;
|
||||
height: 32mm;
|
||||
background: #fff;
|
||||
padding: 2mm;
|
||||
border-radius: 2mm;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.qr img {
|
||||
bredd: 100%;
|
||||
höjd: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cta-text h3 {
|
||||
teckenstorlek: 14,5pt;
|
||||
färg: #38bdf8;
|
||||
typsnittsvikt: 700;
|
||||
marginal-botten: 2mm;
|
||||
font-size: 14.5pt;
|
||||
color: #38bdf8;
|
||||
font-weight: 700;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
|
||||
.cta-text p {
|
||||
teckenstorlek: 11pt;
|
||||
färg: #94a3b8;
|
||||
Linjehöjd: 1,5;
|
||||
font-size: 11pt;
|
||||
color: #94a3b8;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
mellanrum: 2mm;
|
||||
marginal-topp: 3mm;
|
||||
gap: 2mm;
|
||||
margin-top: 3mm;
|
||||
}
|
||||
|
||||
.tag {
|
||||
teckenstorlek: 9,5pt;
|
||||
typsnittsvikt: 600;
|
||||
bokstavsavstånd: 0.04em;
|
||||
text-transform: versaler;
|
||||
färg: #64748b;
|
||||
font-size: 9.5pt;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: #64748b;
|
||||
border: 1px solid rgba(100, 116, 139, 0.4);
|
||||
gränsradie: 1,5 mm;
|
||||
stoppning: 1 mm 2,5 mm;
|
||||
border-radius: 1.5mm;
|
||||
padding: 1mm 2.5mm;
|
||||
}
|
||||
|
||||
sidfot {
|
||||
footer {
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.15);
|
||||
stoppning-topp: 3mm;
|
||||
marginal-topp: auto;
|
||||
flex-krympning: 0;
|
||||
teckenstorlek: 9,5pt;
|
||||
Linjehöjd: 1,5;
|
||||
färg: #64748b;
|
||||
position: relativ;
|
||||
padding-top: 3mm;
|
||||
margin-top: auto;
|
||||
flex-shrink: 0;
|
||||
font-size: 9.5pt;
|
||||
line-height: 1.5;
|
||||
color: #64748b;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
sidfot strong {
|
||||
färg: #94a3b8;
|
||||
typsnittsvikt: 600;
|
||||
footer strong {
|
||||
color: #94a3b8;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -314,7 +314,7 @@
|
||||
<strong>också offline</strong> användbar till sjöss.
|
||||
</p>
|
||||
|
||||
<section class="features" aria-label="Funktionen">
|
||||
<section class="features" aria-label="Funktioner">
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Resdagar i nautiskt loggboksformat (hamn, väder, segel, besättning, bränslenivåer)</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Offline-kompatibel PWA - körs på alla smartphones och surfplattor</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Enkel lösenordsfri Passkey-inloggning</span></div>
|
||||
@@ -328,22 +328,22 @@
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Krypterad säkerhetskopiering och återställning</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Dela loggbok med vänner</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Valfritt antal fartyg och loggböcker</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 16 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="16" height="10" fill="#006AA7"/><rect x="5" width="2" height="10" fill="#FECC00"/><rect y="4" width="16" height="2" fill="#FECC00"/></svg>Svenska</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>Engelsk</span></span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>English</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="37" height="28" fill="#C8102E"/><rect x="12" width="4" height="28" fill="#fff"/><rect y="12" width="37" height="4" fill="#fff"/></svg>Dansk</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 16 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="16" height="10" fill="#006AA7"/><rect x="5" width="2" height="10" fill="#FECC00"/><rect y="4" width="16" height="2" fill="#FECC00"/></svg>Svenska</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="22" height="16" fill="#BA0C2F"/><rect x="6" width="4" height="16" fill="#fff"/><rect y="6" width="22" height="4" fill="#fff"/><rect x="7" width="2" height="16" fill="#00205B"/><rect y="7" width="22" height="2" fill="#00205B"/></svg>Norsk</span></span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>3 teman, vart och ett med en ljus och en mörk variant</span></div>
|
||||
<div class="feature"><span class="feature-icon">✦</span><span>Tillverkad i Kiel.Sailing.City..</span></div>
|
||||
</section>
|
||||
|
||||
<section class="screenshots" aria-label="App-Screenshots">
|
||||
<section class="screenshots" aria-label="Appens skärmdumpar">
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-login.png" alt="Anmeldung mit Passkey und Demo" />
|
||||
<img src="assets/screenshot-login.png" alt="Registrering med Passkey och demo" />
|
||||
<figcaption class="screenshot-caption">Registrering & Passkey</figcaption>
|
||||
</figure>
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-logbook.png" alt="Logbuch-Journal mit Reisetagen" />
|
||||
<img src="assets/screenshot-logbook.png" alt="Loggboksdagbok med resedagar" />
|
||||
<figcaption class="screenshot-caption">Loggboksjournal</figcaption>
|
||||
</figure>
|
||||
<figure class="screenshot-card">
|
||||
<img src="assets/screenshot-vessel.png" alt="Schiffs-Stammdaten mit Yachtfoto" />
|
||||
<img src="assets/screenshot-vessel.png" alt="Fartygsdata med foto av yacht" />
|
||||
<figcaption class="screenshot-caption">Fartygsdata</figcaption>
|
||||
</figure>
|
||||
</section>
|
||||
@@ -359,7 +359,7 @@
|
||||
|
||||
<section class="cta">
|
||||
<div class="qr">
|
||||
<img src="assets/qr-kapteins-daagbok.eu.png" alt="QR-Code: kapteins-daagbok.eu" />
|
||||
<img src="assets/qr-kapteins-daagbok.eu.png" alt="QR-kod: kapteins-daagbok.eu" />
|
||||
</div>
|
||||
<div class="cta-text">
|
||||
<h3>kapteins-daagbok.eu</h3>
|
||||
@@ -374,7 +374,7 @@
|
||||
|
||||
<footer>
|
||||
<strong>Avtryck</strong><br />
|
||||
KnorrLabs - Markus F.J. Busche - Knorrstr. 16 · 24106 Kiel - elpatron+kd@mailbox.org
|
||||
KnorrLabs · Markus F.J. Busche · Knorrstr. 16 · 24106 Kiel · elpatron+kd@mailbox.org
|
||||
</footer>
|
||||
</article>
|
||||
</body>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 MiB After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 MiB After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 MiB After Width: | Height: | Size: 1.3 MiB |
@@ -31,7 +31,8 @@ export const NO_TRANSLATE_TERMS = [
|
||||
'iPad',
|
||||
'iPhone',
|
||||
'Android',
|
||||
'Knorrstr. 16 · 24106 Kiel'
|
||||
'Knorrstr. 16 · 24106 Kiel',
|
||||
'KnorrLabs · Markus F.J. Busche · Knorrstr. 16 · 24106 Kiel · elpatron+kd@mailbox.org'
|
||||
]
|
||||
|
||||
const PLACEHOLDER_RE = /\{\{[^}]+\}\}/g
|
||||
|
||||
+79
-34
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Generate localized beta flyer HTML files from the German master via DeepL.
|
||||
* Generate localized beta flyer HTML from the German master via DeepL.
|
||||
* Only visible body text and <title> are translated — CSS/HTML structure stay intact.
|
||||
*
|
||||
* Usage: node scripts/translate-flyer.mjs [--lang da,sv,nb]
|
||||
*/
|
||||
@@ -20,43 +21,89 @@ const TARGETS = {
|
||||
nb: { code: 'NB', htmlLang: 'nb', file: 'beta-flyer.nb.html' }
|
||||
}
|
||||
|
||||
/** Extract translatable text segments from HTML (text nodes only). */
|
||||
function extractSegments(html) {
|
||||
const LANG_LIST_BLOCK = `<span class="lang-list"><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>English</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="37" height="28" fill="#C8102E"/><rect x="12" width="4" height="28" fill="#fff"/><rect y="12" width="37" height="4" fill="#fff"/></svg>Dansk</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 16 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="16" height="10" fill="#006AA7"/><rect x="5" width="2" height="10" fill="#FECC00"/><rect y="4" width="16" height="2" fill="#FECC00"/></svg>Svenska</span><span class="lang-sep">·</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="22" height="16" fill="#BA0C2F"/><rect x="6" width="4" height="16" fill="#fff"/><rect y="6" width="22" height="4" fill="#fff"/><rect x="7" width="2" height="16" fill="#00205B"/><rect y="7" width="22" height="2" fill="#00205B"/></svg>Norsk</span></span>`
|
||||
|
||||
/** Pull translatable strings from visible content only (never from <style>). */
|
||||
function collectSegments(html) {
|
||||
const segments = []
|
||||
const re = />([^<]+)</g
|
||||
|
||||
const titleMatch = html.match(/<title>([^<]*)<\/title>/i)
|
||||
if (titleMatch?.[1]?.trim()) {
|
||||
segments.push({ kind: 'title', original: titleMatch[1] })
|
||||
}
|
||||
|
||||
const bodyMatch = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i)
|
||||
const bodyHtml = bodyMatch?.[1] ?? ''
|
||||
|
||||
const textRe = />([^<]+)</g
|
||||
let match
|
||||
while ((match = re.exec(html)) !== null) {
|
||||
while ((match = textRe.exec(bodyHtml)) !== null) {
|
||||
const text = match[1]
|
||||
if (!text.trim()) continue
|
||||
if (/^\s*$/.test(text)) continue
|
||||
segments.push({ text, index: segments.length })
|
||||
// Legal imprint stays identical in all locales
|
||||
if (text.includes('KnorrLabs')) continue
|
||||
segments.push({ kind: 'text', original: text })
|
||||
}
|
||||
|
||||
const ariaRe = /aria-label="([^"]+)"/g
|
||||
while ((match = ariaRe.exec(bodyHtml)) !== null) {
|
||||
segments.push({ kind: 'aria', original: match[1] })
|
||||
}
|
||||
|
||||
const altRe = /alt="([^"]+)"/g
|
||||
while ((match = altRe.exec(bodyHtml)) !== null) {
|
||||
segments.push({ kind: 'alt', original: match[1] })
|
||||
}
|
||||
|
||||
return segments
|
||||
}
|
||||
|
||||
function replaceSegments(html, originals, translated) {
|
||||
function applySegments(html, segments, translated) {
|
||||
let result = html
|
||||
for (let i = 0; i < originals.length; i++) {
|
||||
const from = originals[i].text
|
||||
const to = translated[i]
|
||||
if (from === to) continue
|
||||
result = result.replace(`>${from}<`, `>${to}<`)
|
||||
}
|
||||
|
||||
segments.forEach((segment, index) => {
|
||||
const next = translated[index]
|
||||
if (segment.original === next) return
|
||||
|
||||
switch (segment.kind) {
|
||||
case 'title':
|
||||
result = result.replace(
|
||||
`<title>${segment.original}</title>`,
|
||||
`<title>${next}</title>`
|
||||
)
|
||||
break
|
||||
case 'text': {
|
||||
const needle = `>${segment.original}<`
|
||||
const pos = result.indexOf(needle)
|
||||
if (pos === -1) return
|
||||
result = `${result.slice(0, pos)}>${next}<${result.slice(pos + needle.length)}`
|
||||
break
|
||||
}
|
||||
case 'aria':
|
||||
result = result.replace(
|
||||
`aria-label="${segment.original}"`,
|
||||
`aria-label="${next}"`
|
||||
)
|
||||
break
|
||||
case 'alt':
|
||||
result = result.replace(
|
||||
`alt="${segment.original}"`,
|
||||
`alt="${next}"`
|
||||
)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function patchLanguageFeature(html, lang) {
|
||||
const langBlocks = {
|
||||
da: `<span class="lang-item"><svg class="feature-flag" viewBox="0 0 37 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="37" height="28" fill="#C8102E"/><rect x="12" width="4" height="28" fill="#fff"/><rect y="12" width="37" height="4" fill="#fff"/></svg>Dansk</span>`,
|
||||
sv: `<span class="lang-item"><svg class="feature-flag" viewBox="0 0 16 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="16" height="10" fill="#006AA7"/><rect x="5" width="2" height="10" fill="#FECC00"/><rect y="4" width="16" height="2" fill="#FECC00"/></svg>Svenska</span>`,
|
||||
nb: `<span class="lang-item"><svg class="feature-flag" viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="22" height="16" fill="#BA0C2F"/><rect x="6" width="4" height="16" fill="#fff"/><rect y="6" width="22" height="4" fill="#fff"/><rect x="7" width="2" height="16" fill="#00205B"/><rect y="7" width="22" height="2" fill="#00205B"/></svg>Norsk</span>`
|
||||
}
|
||||
|
||||
const deEnBlock =
|
||||
/<span class="lang-list">[\s\S]*?<\/span><\/span><\/div>/
|
||||
const replacement = `<span class="lang-list">${langBlocks[lang]}<span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 5 3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="5" height="1" fill="#000"/><rect y="1" width="5" height="1" fill="#D00"/><rect y="2" width="5" height="1" fill="#FFCE00"/></svg>Deutsch</span><span class="lang-sep">&</span><span class="lang-item"><svg class="feature-flag" viewBox="0 0 60 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><clipPath id="gb-a"><path d="M0 0v30h60V0z"/></clipPath><clipPath id="gb-b"><path d="M30 15h30v15zv15H0z"/></clipPath><g clip-path="url(#gb-a)"><path d="M0 0v30h60V0z" fill="#012169"/><path d="M0 0l60 30m0-30L0 30" stroke="#fff" stroke-width="6"/><path d="M0 0l60 30m0-30L0 30" clip-path="url(#gb-b)" stroke="#C8102E" stroke-width="4"/><path d="M30 0v30M0 15h60" stroke="#fff" stroke-width="10"/><path d="M30 0v30M0 15h60" stroke="#C8102E" stroke-width="6"/></g></svg>Engelsk</span></span></div>`
|
||||
|
||||
return html.replace(deEnBlock, replacement)
|
||||
function patchLanguageFeature(html) {
|
||||
return html.replace(
|
||||
/(<div class="feature"><span class="feature-icon">✦<\/span>)<span class="lang-list">[\s\S]*?<\/span>(<\/div>)/,
|
||||
`$1${LANG_LIST_BLOCK}$2`
|
||||
)
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
@@ -73,8 +120,10 @@ async function main() {
|
||||
const langs = parseArgs(process.argv)
|
||||
const apiKey = loadEnvKey()
|
||||
const sourceHtml = await readFile(sourcePath, 'utf8')
|
||||
const segments = extractSegments(sourceHtml)
|
||||
const texts = segments.map((s) => s.text)
|
||||
const segments = collectSegments(sourceHtml)
|
||||
const texts = segments.map((s) => s.original)
|
||||
|
||||
console.log(`Translating ${texts.length} visible strings per locale…`)
|
||||
|
||||
for (const lang of langs) {
|
||||
const target = TARGETS[lang]
|
||||
@@ -90,13 +139,9 @@ async function main() {
|
||||
batchSize: 20
|
||||
})
|
||||
|
||||
let html = replaceSegments(sourceHtml, segments, translated)
|
||||
let html = applySegments(sourceHtml, segments, translated)
|
||||
html = html.replace(/<html lang="de">/, `<html lang="${target.htmlLang}">`)
|
||||
html = html.replace(
|
||||
/<title>Kapteins Daagbok — Beta-Flyer<\/title>/,
|
||||
`<title>Kapteins Daagbok — Beta-Flyer (${target.htmlLang.toUpperCase()})</title>`
|
||||
)
|
||||
html = patchLanguageFeature(html, lang)
|
||||
html = patchLanguageFeature(html)
|
||||
|
||||
const outPath = resolve(repoRoot, 'docs/marketing', target.file)
|
||||
await writeFile(outPath, html, 'utf8')
|
||||
|
||||
Reference in New Issue
Block a user