Les meta `og:image` / `twitter:image` ajoutés en v7.69.0 pointaient vers une URL relative (`/static/img/logo-512.jpg`). Les crawlers — LinkedIn, Slack, Discord, iMessage — ignorent une URL relative : la carte de partage de FlowDeck était donc vide partout où un lien est collé. Correction via le motif déjà en place dans `app/templating.py` : un global Jinja `app_base_url()` construit à partir de `settings.app_base_url`, qui est LA MÊME source que les liens de partage de pages (`collaboration.py:32`). Si cette valeur est mal renseignée, ces liens l'étaient déjà — comportement cohérent plutôt qu'une deuxième source de vérité à maintenir. Lecture paresseuse de `settings` dans la fonction, à l'image de `_plugin_enabled` : un import au chargement du module créerait un import circulaire. Rendu vérifié sur l'instance déployée : og:image" content="http://localhost:8080/static/img/logo-512.jpg Tests : `test_og_image_url_is_absolute_via_base_url` vérifie le global ET l'absence de la forme relative dans les deux templates. Piège évité au passage — la forme absolue CONTIENT l'ancienne en sous-chaîne, donc l'assertion négative porte sur `content="/static/img/` (le guillemet avant la barre) et non sur l'URL complète. pytest 1413 passed / 0 failed · ruff OK · OpenAPI 526 chemins / 7.69.1 e2e 14/14 verts sur l'instance redéployée
255 lines
8.1 KiB
HTML
255 lines
8.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" data-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
{% from '_icons.html' import fd_icon %}
|
|
<title>FlowDeck — All-in-one workspace</title>
|
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
|
<link rel="manifest" href="/static/manifest.json">
|
|
<meta name="theme-color" content="#191919">
|
|
<link rel="apple-touch-icon" href="/static/icons/apple-touch-icon.png">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<!-- v7.69 : identité visuelle — la landing est la page la plus partagée -->
|
|
<meta name="description" content="FlowDeck — espace de travail style Notion auto-hébergé, intégré à Gitea/GitHub. Éditeur de blocs, Kanban, bases de données.">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:site_name" content="FlowDeck">
|
|
<meta property="og:title" content="FlowDeck — votre espace Notion auto-hébergé">
|
|
<meta property="og:description" content="Éditeur de blocs, Kanban, bases de données et intégration Gitea/GitHub, sur votre propre serveur.">
|
|
<meta property="og:image" content="{{ app_base_url() }}/static/img/logo-512.jpg">
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:title" content="FlowDeck — votre espace Notion auto-hébergé">
|
|
<meta name="twitter:description" content="Éditeur de blocs, Kanban, bases de données et intégration Gitea/GitHub.">
|
|
<meta name="twitter:image" content="{{ app_base_url() }}/static/img/logo-512.jpg">
|
|
<style>
|
|
:root {
|
|
--bg: #191919;
|
|
--bg-card: #1e1e1e;
|
|
--text: #e0e0e0;
|
|
--text-dim: #999;
|
|
--accent: #2383E2;
|
|
--accent-hover: #2C8CEB;
|
|
--border: rgba(255,255,255,.06);
|
|
--radius: 12px;
|
|
}
|
|
*{margin:0;padding:0;box-sizing:border-box;}
|
|
body{
|
|
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
|
|
background:var(--bg);
|
|
color:var(--text);
|
|
min-height:100vh;
|
|
display:flex;
|
|
flex-direction:column;
|
|
}
|
|
/* Nav */
|
|
.landing-nav{
|
|
display:flex;
|
|
align-items:center;
|
|
justify-content:space-between;
|
|
padding:16px 32px;
|
|
border-bottom:1px solid var(--border);
|
|
}
|
|
.landing-logo{
|
|
font-size:20px;
|
|
font-weight:700;
|
|
display:flex;
|
|
align-items:center;
|
|
gap:8px;
|
|
text-decoration:none;
|
|
color:var(--text);
|
|
}
|
|
.landing-nav-actions{
|
|
display:flex;
|
|
gap:12px;
|
|
align-items:center;
|
|
}
|
|
.btn{
|
|
padding:10px 20px;
|
|
border-radius:8px;
|
|
font-size:14px;
|
|
font-weight:500;
|
|
cursor:pointer;
|
|
text-decoration:none;
|
|
border:none;
|
|
transition:all .15s;
|
|
}
|
|
.btn-primary{
|
|
background:var(--accent);
|
|
color:#fff;
|
|
}
|
|
.btn-primary:hover{background:var(--accent-hover);}
|
|
.btn-secondary{
|
|
background:transparent;
|
|
color:var(--text);
|
|
border:1px solid var(--border);
|
|
}
|
|
.btn-secondary:hover{background:rgba(255,255,255,.05);}
|
|
|
|
/* Hero */
|
|
.hero{
|
|
text-align:center;
|
|
padding:80px 32px 60px;
|
|
max-width:720px;
|
|
margin:0 auto;
|
|
}
|
|
.hero h1{
|
|
font-size:clamp(2rem,5vw,3.2rem);
|
|
font-weight:800;
|
|
letter-spacing:-.5px;
|
|
margin-bottom:16px;
|
|
line-height:1.2;
|
|
}
|
|
.hero .gradient-text{
|
|
background:linear-gradient(135deg,#2383E2,#6C5CE7);
|
|
-webkit-background-clip:text;
|
|
-webkit-text-fill-color:transparent;
|
|
background-clip:text;
|
|
}
|
|
.hero p{
|
|
font-size:18px;
|
|
color:var(--text-dim);
|
|
line-height:1.6;
|
|
margin-bottom:32px;
|
|
}
|
|
.hero-actions{
|
|
display:flex;
|
|
gap:12px;
|
|
justify-content:center;
|
|
flex-wrap:wrap;
|
|
}
|
|
.hero-actions .btn{
|
|
font-size:15px;
|
|
padding:12px 28px;
|
|
}
|
|
|
|
/* v7.69 : identité visuelle */
|
|
.brand-mark{border-radius:7px;flex:none;}
|
|
.hero-visual{
|
|
max-width:1060px;
|
|
margin:0 auto 72px;
|
|
padding:0 32px;
|
|
}
|
|
.hero-visual img{
|
|
width:100%;
|
|
height:auto;
|
|
display:block;
|
|
border-radius:14px;
|
|
border:1px solid var(--border);
|
|
box-shadow:0 30px 70px -30px rgba(0,0,0,.5);
|
|
}
|
|
|
|
/* Features grid */
|
|
.features{
|
|
display:grid;
|
|
grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
|
|
gap:16px;
|
|
max-width:1000px;
|
|
margin:0 auto;
|
|
padding:0 32px 60px;
|
|
}
|
|
.feature-card{
|
|
background:var(--bg-card);
|
|
border:1px solid var(--border);
|
|
border-radius:var(--radius);
|
|
padding:28px 24px;
|
|
transition:border-color .15s;
|
|
}
|
|
.feature-card:hover{border-color:rgba(255,255,255,.12);}
|
|
.feature-icon{font-size:28px;margin-bottom:12px;}
|
|
.feature-card h3{font-size:16px;font-weight:600;margin-bottom:8px;}
|
|
.feature-card p{font-size:14px;color:var(--text-dim);line-height:1.5;}
|
|
|
|
/* Footer */
|
|
.landing-footer{
|
|
margin-top:auto;
|
|
text-align:center;
|
|
padding:32px;
|
|
border-top:1px solid var(--border);
|
|
font-size:13px;
|
|
color:var(--text-dim);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="landing-nav">
|
|
<a href="/" class="landing-logo">
|
|
<img class="brand-mark" src="/static/img/logo.webp" alt="" width="26" height="26"> FlowDeck
|
|
</a>
|
|
<div class="landing-nav-actions">
|
|
<a href="/auth/login?provider=local" class="btn btn-secondary">Log in</a>
|
|
<a href="/auth/register" class="btn btn-primary">Get started free</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<section class="hero">
|
|
<h1>Your <span class="gradient-text">Notion-style</span> workspace,<br>self-hosted & integrated</h1>
|
|
<p>
|
|
Write, organize, and collaborate — with block-based editing,
|
|
Kanban boards, databases, and deep Gitea/GitHub integration.
|
|
All on your own server.
|
|
</p>
|
|
<div class="hero-actions">
|
|
<a href="/auth/register" class="btn btn-primary">Get started — it's free</a>
|
|
<a href="/auth/login?provider=local" class="btn btn-secondary">I already have an account</a>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- v7.69 : bannière du projet (asset optimisé : WebP 22 KB, JPEG en secours) -->
|
|
<div class="hero-visual">
|
|
<picture>
|
|
<source srcset="/static/img/banner.webp" type="image/webp">
|
|
<img src="/static/img/banner.jpg" alt="FlowDeck — éditeur de blocs, Kanban et bases de données" width="2400" height="793" loading="lazy" decoding="async">
|
|
</picture>
|
|
</div>
|
|
|
|
<div class="features">
|
|
<div class="feature-card">
|
|
<div class="feature-icon">{{ fd_icon("edit",24) }}</div>
|
|
<h3>Block Editor</h3>
|
|
<p>Notion-style editor with slash commands, markdown shortcuts, headings, code blocks, to-dos, and more.</p>
|
|
</div>
|
|
<div class="feature-card">
|
|
<div class="feature-icon">{{ fd_icon("bar-chart",24) }}</div>
|
|
<h3>Kanban & Tables</h3>
|
|
<p>Visual project management with drag-drop boards, table views, and database collections.</p>
|
|
</div>
|
|
<div class="feature-card">
|
|
<div class="feature-icon">{{ fd_icon("link",24) }}</div>
|
|
<h3>Gitea & GitHub</h3>
|
|
<p>Browse repos, edit files, commit changes — all from your workspace sidebar.</p>
|
|
</div>
|
|
<div class="feature-card">
|
|
<div class="feature-icon">{{ fd_icon("globe",24) }}</div>
|
|
<h3>Publish to Web</h3>
|
|
<p>One-click publish any page to a public URL. Share with anyone, no account needed.</p>
|
|
</div>
|
|
<div class="feature-card">
|
|
<div class="feature-icon">{{ fd_icon("lock",24) }}</div>
|
|
<h3>Self-Hosted</h3>
|
|
<p>Your data stays on your server. No vendor lock-in, full control, Docker single-container deploy.</p>
|
|
</div>
|
|
<div class="feature-card">
|
|
<div class="feature-icon">{{ fd_icon("zap",24) }}</div>
|
|
<h3>Fast & Light</h3>
|
|
<p>Alpine.js + FastAPI + SQLite. No React bloat, no Node.js needed. Sub-100ms page loads.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<footer class="landing-footer">
|
|
FlowDeck v4.0.1 — Open source · Self-hosted · Notion-compatible
|
|
</footer>
|
|
|
|
<script data-cfasync="false" nonce="{{ csp_nonce() }}">
|
|
(function() {
|
|
if (!('serviceWorker' in navigator)) return;
|
|
window.addEventListener('load', function() {
|
|
navigator.serviceWorker.register('/sw.js').catch(function() {});
|
|
});
|
|
})();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|