chore(landing): retire the 2.0 launch banner and refresh the social preview (#576)
Removes the temporary 2.0 launch banner and README note, and refreshes the social/OG card to the current landing hero (synced to landing/web/docs og-image.png).
@@ -2,14 +2,6 @@
|
||||
<img src="branding/social-preview.png" width="800" alt="SnapOtter - A Self-Hosted File Manipulation Suite">
|
||||
</p>
|
||||
|
||||
<!-- TEMP: 2.0.0 launch + migration + Discord note. Trim a few weeks after release, once it's old news. -->
|
||||
> [!IMPORTANT]
|
||||
> **SnapOtter 2.0 is here.** 200+ tools across five modalities (image, video, audio, PDF, and files), durable background jobs, on-demand local AI, and a one-command `docker run`. See the [release notes](https://github.com/snapotter-hq/SnapOtter/releases/tag/v2.0.0).
|
||||
>
|
||||
> **Coming from 1.x?** Many of you have trusted SnapOtter since day one, and your feedback and suggestions shaped everything that followed. 2.0 is a big step, and we worked to make sure it doesn't break what you already depend on. Your accounts, saved files, settings, API keys, and pipelines carry over automatically on first boot, and your old database is never modified. We wrote a full [migration guide](./MIGRATING.md) so the move is safe and boring.
|
||||
>
|
||||
> I'll be on [Discord](https://discord.gg/hr3s7HPUsr) more than usual this week, so if you need a hand with the upgrade or anything else, come say hi and I'll get back to you quickly. Thank you for being here.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://hub.docker.com/r/snapotter/snapotter"><img src="https://img.shields.io/docker/v/snapotter/snapotter?label=Docker%20Hub&logo=docker" alt="Docker Hub"></a>
|
||||
<a href="https://github.com/orgs/snapotter-hq/packages/container/package/snapotter"><img src="https://img.shields.io/badge/GHCR-ghcr.io%2Fsnapotter--hq%2Fsnapotter-blue?logo=github" alt="GHCR"></a>
|
||||
|
||||
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 382 KiB |
@@ -1,131 +0,0 @@
|
||||
---
|
||||
// TEMP: 2.0 launch banner. Remove a few weeks after release, once it's old news.
|
||||
// Dismissal is remembered in localStorage; a render-blocking check in Base.astro's
|
||||
// <head> sets data-lb-dismissed before paint so returning visitors see no flash.
|
||||
const RELEASE = "https://github.com/snapotter-hq/SnapOtter/releases/tag/v2.0.0";
|
||||
---
|
||||
|
||||
<aside class="lb-root" data-lb>
|
||||
<div class="lb-burst" aria-hidden="true">NEW!</div>
|
||||
<div class="lb-marquee" aria-hidden="true">
|
||||
<div class="lb-track">
|
||||
<span>★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ </span>
|
||||
<span>★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ SnapOtter <b>2.0</b> is HERE ★ </span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="lb-btn" href={RELEASE} target="_blank" rel="noopener noreferrer" aria-label="See the SnapOtter 2.0 release notes">Click here!</a>
|
||||
<button class="lb-x" type="button" data-lb-close aria-label="Dismiss announcement">✕</button>
|
||||
</aside>
|
||||
|
||||
<style is:global>
|
||||
:root { --lb-h: 48px; }
|
||||
html[data-lb-dismissed] { --lb-h: 0px; }
|
||||
|
||||
/* Push the fixed navbar and all page content down by the banner height, so
|
||||
the banner sits above the nav without overlapping. Collapses when dismissed. */
|
||||
body { padding-top: var(--lb-h); transition: padding-top 0.28s ease; }
|
||||
nav.fixed { top: var(--lb-h); transition: top 0.28s ease; }
|
||||
|
||||
.lb-root {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 60;
|
||||
height: var(--lb-h);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 42px 0 10px;
|
||||
background: #1a1210;
|
||||
background-image: repeating-linear-gradient(45deg, rgba(240, 149, 80, 0.16) 0 8px, transparent 8px 16px);
|
||||
border-top: 3px ridge #f0a24e;
|
||||
border-bottom: 3px solid #0b0704;
|
||||
box-shadow: 0 6px 18px -10px rgba(0, 0, 0, 0.5);
|
||||
font-family: "Comic Sans MS", "Trebuchet MS", var(--font-body, sans-serif);
|
||||
opacity: 1;
|
||||
transition: opacity 0.22s ease;
|
||||
}
|
||||
html[data-lb-dismissed] .lb-root { opacity: 0; visibility: hidden; }
|
||||
|
||||
.lb-burst {
|
||||
flex: 0 0 auto;
|
||||
color: #7a1503;
|
||||
font-weight: 900;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.02em;
|
||||
background: #ffd34e;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
text-align: center;
|
||||
clip-path: polygon(50% 0, 61% 12%, 77% 6%, 78% 23%, 95% 25%, 86% 40%, 100% 50%, 86% 60%, 95% 75%, 78% 77%, 77% 94%, 61% 88%, 50% 100%, 39% 88%, 23% 94%, 22% 77%, 5% 75%, 14% 60%, 0 50%, 14% 40%, 5% 25%, 22% 23%, 23% 6%, 39% 12%);
|
||||
animation: lb-spin 7s linear infinite;
|
||||
box-shadow: 0 0 0 2px #b5471b;
|
||||
}
|
||||
.lb-marquee { flex: 1 1 auto; overflow: hidden; white-space: nowrap; }
|
||||
.lb-track { display: inline-flex; animation: lb-slide 22s linear infinite; will-change: transform; }
|
||||
.lb-track span { color: #fff6da; font-weight: 700; font-size: 15px; text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.55); }
|
||||
.lb-track b { color: #ffe86b; }
|
||||
|
||||
.lb-btn {
|
||||
flex: 0 0 auto;
|
||||
font-weight: 800;
|
||||
font-size: 12.5px;
|
||||
color: #12233b;
|
||||
background: linear-gradient(#fff, #cfd8e6);
|
||||
border: 2px outset #eef;
|
||||
padding: 5px 11px;
|
||||
border-radius: 3px;
|
||||
text-decoration: none;
|
||||
animation: lb-blink 1.1s steps(2, start) infinite;
|
||||
}
|
||||
.lb-btn:hover { background: linear-gradient(#fff, #dde6f2); }
|
||||
|
||||
.lb-x {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
font-weight: 900;
|
||||
font-size: 12px;
|
||||
color: #12233b;
|
||||
background: linear-gradient(#fff, #c8c8c8);
|
||||
border: 2px outset #fff;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 0;
|
||||
}
|
||||
.lb-x:active { border-style: inset; }
|
||||
|
||||
@keyframes lb-spin { to { transform: rotate(360deg); } }
|
||||
@keyframes lb-slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }
|
||||
@keyframes lb-blink { 50% { opacity: 0.4; } }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.lb-track, .lb-burst, .lb-btn { animation: none !important; }
|
||||
body, nav.fixed, .lb-root { transition: none !important; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
const KEY = "snapotter-v2-banner";
|
||||
const root = document.querySelector("[data-lb]");
|
||||
if (!root) return;
|
||||
const close = root.querySelector("[data-lb-close]");
|
||||
close?.addEventListener("click", () => {
|
||||
try {
|
||||
localStorage.setItem(KEY, "dismissed");
|
||||
} catch (e) {
|
||||
/* private mode / storage disabled: just hide for this session */
|
||||
}
|
||||
document.documentElement.setAttribute("data-lb-dismissed", "");
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -34,28 +34,25 @@ const CONTRIBUTE_URL = "https://docs.snapotter.com/guide/translations";
|
||||
)}
|
||||
|
||||
<style is:global>
|
||||
/* The banner is a fixed bar stacked directly below the 2.0 launch banner and
|
||||
above the fixed navbar, so it is both visible and its dismiss button is
|
||||
clickable. It drives --mt-h so the navbar and page content shift down by its
|
||||
height; --mt-h collapses to 0 on English pages and after dismissal. The
|
||||
launch banner is temporary, so this composes with --lb-h via calc(). */
|
||||
/* A fixed bar above the fixed navbar, so it is both visible and its dismiss
|
||||
button is clickable. It drives --mt-h so the navbar and page content shift
|
||||
down by its height; --mt-h collapses to 0 on English pages and after
|
||||
dismissal. */
|
||||
:root { --mt-h: 0px; }
|
||||
|
||||
.mt-banner {
|
||||
position: fixed;
|
||||
top: var(--lb-h, 0px);
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 55; /* above the navbar (z-50), below the launch banner (z-60) */
|
||||
z-index: 55; /* above the navbar (z-50) */
|
||||
}
|
||||
|
||||
html:has(.mt-banner:not([hidden])) { --mt-h: 36px; }
|
||||
|
||||
/* Shift the fixed navbar and page content down by the launch + MT banner
|
||||
heights. These selectors also live in LaunchBanner.astro; the combined
|
||||
calc() here supersedes them without fighting the cascade. */
|
||||
body { padding-top: calc(var(--lb-h, 0px) + var(--mt-h)); }
|
||||
nav.fixed { top: calc(var(--lb-h, 0px) + var(--mt-h)); }
|
||||
/* Shift the fixed navbar and page content down by the banner height. */
|
||||
body { padding-top: var(--mt-h); }
|
||||
nav.fixed { top: var(--mt-h); }
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import "@/styles/globals.css";
|
||||
import { TOOLS } from "@snapotter/shared";
|
||||
import Analytics from "@/components/Analytics.astro";
|
||||
import LaunchBanner from "@/components/LaunchBanner.astro";
|
||||
import MachineTranslationBanner from "@/components/MachineTranslationBanner.astro";
|
||||
import { LANDING_LOCALES, t } from "@/i18n";
|
||||
import { altLinks, dirFor, ogLocale } from "@/lib/i18n-page";
|
||||
@@ -71,16 +70,6 @@ const htmlDir = dirFor(locale);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- TEMP: 2.0 launch banner dismissal. Render-blocking so a returning visitor
|
||||
who closed the banner never sees it flash. Remove with the banner. -->
|
||||
<script is:inline>
|
||||
try {
|
||||
if (localStorage.getItem("snapotter-v2-banner") === "dismissed") {
|
||||
document.documentElement.setAttribute("data-lb-dismissed", "");
|
||||
}
|
||||
} catch (e) {}
|
||||
</script>
|
||||
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={canonical} />
|
||||
@@ -140,7 +129,6 @@ const htmlDir = dirFor(locale);
|
||||
<body>
|
||||
<a href="#main" class="skip-link">{t(locale, "common.skipToContent")}</a>
|
||||
<MachineTranslationBanner locale={locale} />
|
||||
<LaunchBanner />
|
||||
<slot />
|
||||
|
||||
<!-- Scroll-triggered reveal observer -->
|
||||
|
||||
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 382 KiB |