This commit is contained in:
+15
-6
@@ -3,20 +3,29 @@ import type { ReactNode } from "react";
|
|||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "hidden11",
|
title: {
|
||||||
description: "Daily football lineup puzzle with evolving difficulty, sharper clues and shareable results.",
|
default: "hidden11",
|
||||||
|
template: "%s | hidden11",
|
||||||
|
},
|
||||||
|
description: "Daily football lineup puzzle with sharper clues, harder challenges and shareable results.",
|
||||||
metadataBase: new URL("https://hidden11.app"),
|
metadataBase: new URL("https://hidden11.app"),
|
||||||
|
applicationName: "hidden11",
|
||||||
|
alternates: {
|
||||||
|
canonical: "https://hidden11.app",
|
||||||
|
},
|
||||||
|
keywords: ["football puzzle", "soccer puzzle", "daily game", "lineup puzzle", "hidden11"],
|
||||||
icons: {
|
icons: {
|
||||||
icon: "/favicon.svg",
|
icon: "/favicon.svg",
|
||||||
},
|
},
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: "hidden11",
|
title: "hidden11",
|
||||||
description: "Daily football lineup puzzle. Beat Easy, Medium and Hard, then share the card.",
|
description: "Beat Easy, Medium and Hard in the daily football lineup puzzle and share the result.",
|
||||||
url: "https://hidden11.app",
|
url: "https://hidden11.app",
|
||||||
siteName: "hidden11",
|
siteName: "hidden11",
|
||||||
|
locale: "en_US",
|
||||||
images: [
|
images: [
|
||||||
{
|
{
|
||||||
url: "/opengraph-image",
|
url: "https://hidden11.app/opengraph-image",
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 630,
|
height: 630,
|
||||||
alt: "hidden11 daily football puzzle",
|
alt: "hidden11 daily football puzzle",
|
||||||
@@ -27,8 +36,8 @@ export const metadata: Metadata = {
|
|||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
title: "hidden11",
|
title: "hidden11",
|
||||||
description: "Daily football lineup puzzle. Beat Easy, Medium and Hard, then share the card.",
|
description: "Beat Easy, Medium and Hard in the daily football lineup puzzle and share the result.",
|
||||||
images: ["/twitter-image"],
|
images: ["https://hidden11.app/twitter-image"],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+138
-50
@@ -15,48 +15,96 @@ export default function OpenGraphImage() {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
background:
|
background: "linear-gradient(135deg, #04110c 0%, #0d2d1f 42%, #145c3a 100%)",
|
||||||
"radial-gradient(circle at top, #1f8f5d 0%, #0a2e1f 35%, #04110c 100%)",
|
|
||||||
color: "#f7fff9",
|
color: "#f7fff9",
|
||||||
padding: 48,
|
padding: 42,
|
||||||
fontFamily: "Arial",
|
fontFamily: "Arial",
|
||||||
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: -90,
|
||||||
|
right: -90,
|
||||||
|
width: 320,
|
||||||
|
height: 320,
|
||||||
|
borderRadius: 999,
|
||||||
|
background: "rgba(62, 230, 150, 0.18)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: -120,
|
||||||
|
left: -80,
|
||||||
|
width: 360,
|
||||||
|
height: 360,
|
||||||
|
borderRadius: 999,
|
||||||
|
background: "rgba(250, 204, 21, 0.12)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
border: "1px solid rgba(255,255,255,0.14)",
|
border: "1px solid rgba(255,255,255,0.14)",
|
||||||
borderRadius: 28,
|
borderRadius: 34,
|
||||||
padding: 36,
|
padding: 34,
|
||||||
background: "rgba(2, 14, 10, 0.54)",
|
background: "rgba(2, 14, 10, 0.68)",
|
||||||
|
boxShadow: "0 30px 80px rgba(0,0,0,0.28)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex", flexDirection: "column", flex: 1, justifyContent: "space-between" }}>
|
<div style={{ display: "flex", flexDirection: "column", flex: 1, justifyContent: "space-between", paddingRight: 22 }}>
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
width: 120,
|
width: 148,
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
borderRadius: 999,
|
borderRadius: 999,
|
||||||
background: "rgba(255,255,255,0.1)",
|
background: "rgba(255,255,255,0.1)",
|
||||||
padding: "10px 16px",
|
padding: "10px 18px",
|
||||||
fontSize: 20,
|
fontSize: 18,
|
||||||
fontWeight: 700,
|
fontWeight: 900,
|
||||||
letterSpacing: 2,
|
letterSpacing: 2.4,
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Daily
|
Daily Puzzle
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", fontSize: 108, fontWeight: 900, letterSpacing: -4 }}>hidden11</div>
|
|
||||||
<div style={{ display: "flex", maxWidth: 620, fontSize: 34, lineHeight: 1.2, color: "#d7fbe7" }}>
|
<div style={{ display: "flex", alignItems: "flex-end", gap: 8 }}>
|
||||||
Daily football lineup puzzle with Easy, Medium and Hard cards that are actually worth solving.
|
<div style={{ display: "flex", fontSize: 102, fontWeight: 900, letterSpacing: -4 }}>hidden</div>
|
||||||
|
<div style={{ display: "flex", gap: 8, marginBottom: 14 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
width: 34,
|
||||||
|
height: 74,
|
||||||
|
borderRadius: 16,
|
||||||
|
background: "linear-gradient(180deg, #48e7a0 0%, #10b968 100%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
width: 34,
|
||||||
|
height: 74,
|
||||||
|
borderRadius: 16,
|
||||||
|
background: "linear-gradient(180deg, #ffe86a 0%, #facc15 100%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display: "flex", maxWidth: 620, fontSize: 34, lineHeight: 1.18, color: "#d7fbe7" }}>
|
||||||
|
Daily football lineup puzzle with clues, history links and difficulty levels that actually escalate.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "flex", gap: 16 }}>
|
<div style={{ display: "flex", gap: 14 }}>
|
||||||
{["Easy", "Medium", "Hard"].map((label, index) => (
|
{["Easy", "Medium", "Hard"].map((label, index) => (
|
||||||
<div
|
<div
|
||||||
key={label}
|
key={label}
|
||||||
@@ -64,16 +112,22 @@ export default function OpenGraphImage() {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
width: 168,
|
width: 172,
|
||||||
padding: 18,
|
padding: 18,
|
||||||
borderRadius: 22,
|
borderRadius: 22,
|
||||||
background: index === 2 ? "#d4ff4d" : "rgba(255,255,255,0.09)",
|
background:
|
||||||
|
index === 0
|
||||||
|
? "rgba(72, 231, 160, 0.16)"
|
||||||
|
: index === 1
|
||||||
|
? "rgba(255,255,255,0.09)"
|
||||||
|
: "#d4ff4d",
|
||||||
color: index === 2 ? "#0b1a12" : "#f7fff9",
|
color: index === 2 ? "#0b1a12" : "#f7fff9",
|
||||||
|
border: "1px solid rgba(255,255,255,0.08)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex", fontSize: 18, fontWeight: 800, textTransform: "uppercase" }}>{label}</div>
|
<div style={{ display: "flex", fontSize: 18, fontWeight: 800, textTransform: "uppercase" }}>{label}</div>
|
||||||
<div style={{ display: "flex", fontSize: 16, lineHeight: 1.3, opacity: 0.9 }}>
|
<div style={{ display: "flex", fontSize: 16, lineHeight: 1.3, opacity: 0.9 }}>
|
||||||
{index === 0 ? "Sharper club clues" : index === 1 ? "Less obvious player pool" : "Career-history riddles"}
|
{index === 0 ? "Fast entry" : index === 1 ? "Less obvious pool" : "Career-history riddles"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -83,57 +137,91 @@ export default function OpenGraphImage() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
width: 360,
|
width: 368,
|
||||||
marginLeft: 28,
|
marginLeft: 16,
|
||||||
borderRadius: 28,
|
borderRadius: 28,
|
||||||
padding: 24,
|
padding: 24,
|
||||||
background: "linear-gradient(180deg, rgba(8,41,28,0.95), rgba(5,22,15,0.98))",
|
background: "linear-gradient(180deg, rgba(8,41,28,0.98), rgba(5,22,15,1))",
|
||||||
border: "1px solid rgba(255,255,255,0.12)",
|
border: "1px solid rgba(255,255,255,0.12)",
|
||||||
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 18 }}>
|
||||||
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<div style={{ display: "flex", fontSize: 16, fontWeight: 800, textTransform: "uppercase", letterSpacing: 1.6, color: "#8ddfb6" }}>
|
||||||
|
Today
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex", marginTop: 4, fontSize: 26, fontWeight: 900 }}>
|
||||||
|
hidden11 #124
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
borderRadius: 999,
|
||||||
|
background: "#3ee696",
|
||||||
|
color: "#082015",
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 900,
|
||||||
|
padding: "10px 14px",
|
||||||
|
textTransform: "uppercase",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Shareable
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
gap: 14,
|
gap: 12,
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{[
|
{[
|
||||||
["", "ST", ""],
|
{ label: "Easy", time: "1:24", color: "#3ee696" },
|
||||||
["WING", "", "MID"],
|
{ label: "Medium", time: "2:08", color: "#facc15" },
|
||||||
["", "DEF", ""],
|
{ label: "Hard", time: "3:41", color: "#ffffff" },
|
||||||
["", "GK", ""],
|
].map((card) => (
|
||||||
].map((row, rowIndex) => (
|
<div
|
||||||
<div key={rowIndex} style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
key={card.label}
|
||||||
{row.map((cell, cellIndex) =>
|
style={{
|
||||||
cell ? (
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: 10,
|
||||||
|
borderRadius: 22,
|
||||||
|
background: "rgba(255,255,255,0.06)",
|
||||||
|
border: "1px solid rgba(255,255,255,0.08)",
|
||||||
|
padding: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
|
<div style={{ display: "flex", fontSize: 18, fontWeight: 800, textTransform: "uppercase" }}>{card.label}</div>
|
||||||
|
<div style={{ display: "flex", fontSize: 16, fontWeight: 700, color: "#d7fbe7" }}>{card.time}</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex", gap: 8 }}>
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
<div
|
<div
|
||||||
key={cell}
|
key={index}
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
width: 82,
|
width: 36,
|
||||||
height: 82,
|
height: 36,
|
||||||
borderRadius: 999,
|
borderRadius: 10,
|
||||||
background: (rowIndex + cellIndex) % 2 === 0 ? "#39d98a" : "#facc15",
|
background: card.color,
|
||||||
color: "#08160f",
|
boxShadow: "inset 0 -6px 0 rgba(0,0,0,0.18)",
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: 900,
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
border: "3px solid rgba(255,255,255,0.25)",
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
{cell}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<div key={`${rowIndex}-${cellIndex}`} style={{ display: "flex", width: 82, height: 82 }} />
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display: "flex", marginTop: 16, fontSize: 16, color: "#b8d8c6" }}>hidden11.app</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+39
-8
@@ -7,6 +7,7 @@ import Pitch from "@/components/Pitch";
|
|||||||
import PlayerSearch from "@/components/PlayerSearch";
|
import PlayerSearch from "@/components/PlayerSearch";
|
||||||
import ShareResult from "@/components/ShareResult";
|
import ShareResult from "@/components/ShareResult";
|
||||||
import StatsPanel from "@/components/StatsPanel";
|
import StatsPanel from "@/components/StatsPanel";
|
||||||
|
import { buildShareText, buildShareUrl } from "@/lib/share";
|
||||||
import {
|
import {
|
||||||
DIFFICULTIES,
|
DIFFICULTIES,
|
||||||
MAX_ATTEMPTS,
|
MAX_ATTEMPTS,
|
||||||
@@ -53,6 +54,11 @@ export default function Home() {
|
|||||||
const isFinished = activeProgress.solved || activeProgress.attempts.length >= MAX_ATTEMPTS;
|
const isFinished = activeProgress.solved || activeProgress.attempts.length >= MAX_ATTEMPTS;
|
||||||
const t = useMemo(() => getDictionary(locale), [locale]);
|
const t = useMemo(() => getDictionary(locale), [locale]);
|
||||||
const quote = useMemo(() => quoteForDay(dateKey, locale), [dateKey, locale]);
|
const quote = useMemo(() => quoteForDay(dateKey, locale), [dateKey, locale]);
|
||||||
|
const shareUrl = useMemo(
|
||||||
|
() => buildShareUrl(dateKey, progress, typeof window === "undefined" ? "https://hidden11.app" : window.location.origin),
|
||||||
|
[dateKey, progress],
|
||||||
|
);
|
||||||
|
const shareText = useMemo(() => buildShareText(dateKey, progress, t, shareUrl), [dateKey, progress, shareUrl, t]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedLocale = window.localStorage.getItem("hidden11-locale") as Locale | null;
|
const savedLocale = window.localStorage.getItem("hidden11-locale") as Locale | null;
|
||||||
@@ -167,6 +173,22 @@ export default function Home() {
|
|||||||
window.localStorage.setItem("hidden11-locale", nextLocale);
|
window.localStorage.setItem("hidden11-locale", nextLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function shareCurrentResult() {
|
||||||
|
if (navigator.share) {
|
||||||
|
await navigator.share({
|
||||||
|
title: "hidden11",
|
||||||
|
text: shareText,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.open(
|
||||||
|
`https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}`,
|
||||||
|
"_blank",
|
||||||
|
"noopener,noreferrer",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const actionButtons = (
|
const actionButtons = (
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
<button
|
<button
|
||||||
@@ -341,14 +363,23 @@ export default function Home() {
|
|||||||
<div className="w-full rounded-lg border border-white/10 bg-pitch-950 p-4 shadow-2xl sm:max-w-lg">
|
<div className="w-full rounded-lg border border-white/10 bg-pitch-950 p-4 shadow-2xl sm:max-w-lg">
|
||||||
<div className="mb-3 flex items-center justify-between">
|
<div className="mb-3 flex items-center justify-between">
|
||||||
<h2 className="text-lg font-black text-white">{t.stats}</h2>
|
<h2 className="text-lg font-black text-white">{t.stats}</h2>
|
||||||
<button
|
<div className="flex items-center gap-2">
|
||||||
type="button"
|
<button
|
||||||
onClick={() => setStatsOpen(false)}
|
type="button"
|
||||||
className="h-9 w-9 rounded-full border border-white/15 text-lg font-black text-white transition hover:bg-white/10"
|
onClick={shareCurrentResult}
|
||||||
aria-label={t.closeModal}
|
className="h-9 rounded-full bg-emerald-400 px-4 text-xs font-black uppercase tracking-wide text-pitch-950 transition hover:bg-emerald-300"
|
||||||
>
|
>
|
||||||
×
|
{t.shareNow}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setStatsOpen(false)}
|
||||||
|
className="h-9 w-9 rounded-full border border-white/15 text-lg font-black text-white transition hover:bg-white/10"
|
||||||
|
aria-label={t.closeModal}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<StatsPanel stats={stats} t={t} />
|
<StatsPanel stats={stats} t={t} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default, alt, contentType, size } from "../../result/[shareCode]/opengraph-image";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default, generateMetadata } from "../../result/[shareCode]/page";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default, alt, contentType, size } from "../../result/[shareCode]/twitter-image";
|
||||||
@@ -16,7 +16,6 @@ type ShareResultProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function ShareResult({ dateKey, locale, onClose, progress, quote, stats, t }: ShareResultProps) {
|
export default function ShareResult({ dateKey, locale, onClose, progress, quote, stats, t }: ShareResultProps) {
|
||||||
const [copied, setCopied] = useState(false);
|
|
||||||
const [shared, setShared] = useState(false);
|
const [shared, setShared] = useState(false);
|
||||||
const [origin, setOrigin] = useState("https://hidden11.app");
|
const [origin, setOrigin] = useState("https://hidden11.app");
|
||||||
const shareUrl = useMemo(() => buildShareUrl(dateKey, progress, origin), [dateKey, origin, progress]);
|
const shareUrl = useMemo(() => buildShareUrl(dateKey, progress, origin), [dateKey, origin, progress]);
|
||||||
@@ -26,18 +25,11 @@ export default function ShareResult({ dateKey, locale, onClose, progress, quote,
|
|||||||
setOrigin(window.location.origin);
|
setOrigin(window.location.origin);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function copy() {
|
|
||||||
await navigator.clipboard.writeText(shareText);
|
|
||||||
setCopied(true);
|
|
||||||
window.setTimeout(() => setCopied(false), 1600);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function share() {
|
async function share() {
|
||||||
if (navigator.share) {
|
if (navigator.share) {
|
||||||
await navigator.share({
|
await navigator.share({
|
||||||
title: "hidden11",
|
title: "hidden11",
|
||||||
text: shareText,
|
text: shareText,
|
||||||
url: shareUrl,
|
|
||||||
});
|
});
|
||||||
setShared(true);
|
setShared(true);
|
||||||
window.setTimeout(() => setShared(false), 1600);
|
window.setTimeout(() => setShared(false), 1600);
|
||||||
@@ -98,27 +90,6 @@ export default function ShareResult({ dateKey, locale, onClose, progress, quote,
|
|||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t border-white/10 bg-pitch-950/95 p-4 backdrop-blur">
|
|
||||||
<div className="grid grid-cols-2 gap-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={share}
|
|
||||||
className="h-11 rounded-md bg-emerald-400 px-3 text-sm font-black text-pitch-950 transition hover:bg-emerald-300"
|
|
||||||
>
|
|
||||||
{shared ? t.copied : t.shareNow}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={copy}
|
|
||||||
className="h-11 rounded-md bg-white px-3 text-sm font-black text-pitch-950 transition hover:bg-emerald-100"
|
|
||||||
>
|
|
||||||
{copied ? t.copied : t.copy}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 rounded-md border border-white/10 bg-black/20 px-3 py-2 text-[11px] text-white/65">
|
|
||||||
{shareUrl}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+13
-3
@@ -25,6 +25,8 @@ type SharePayload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function buildShareText(dateKey: string, progress: DailyProgress, t: Dictionary, shareUrl?: string): string {
|
export function buildShareText(dateKey: string, progress: DailyProgress, t: Dictionary, shareUrl?: string): string {
|
||||||
|
const resultUrl = shareUrl ?? "https://hidden11.app";
|
||||||
|
const homeUrl = "https://hidden11.app";
|
||||||
const rows = DIFFICULTIES.map((difficulty) => {
|
const rows = DIFFICULTIES.map((difficulty) => {
|
||||||
const item = progress[difficulty];
|
const item = progress[difficulty];
|
||||||
const label = t.difficulty[difficulty];
|
const label = t.difficulty[difficulty];
|
||||||
@@ -43,10 +45,18 @@ export function buildShareText(dateKey: string, progress: DailyProgress, t: Dict
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
: "⬛⬛⬛⬛⬛";
|
: "⬛⬛⬛⬛⬛";
|
||||||
|
|
||||||
return `${label} ${result} · ${time}\n${grids}`;
|
return `${label.padEnd(6)} ${result} · ${time}\n${grids}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
return [`hidden11 #${getPuzzleNumber(dateKey)}`, "", ...rows, "", shareUrl ?? "https://hidden11.app"].join("\n");
|
return [
|
||||||
|
"┏━ hidden11.app ━┓",
|
||||||
|
`⚽ hidden11 #${getPuzzleNumber(dateKey)}`,
|
||||||
|
"",
|
||||||
|
...rows,
|
||||||
|
"",
|
||||||
|
`Play: ${homeUrl}`,
|
||||||
|
`Result: ${resultUrl}`,
|
||||||
|
].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildShareUrl(dateKey: string, progress: DailyProgress, origin = "https://hidden11.app"): string {
|
export function buildShareUrl(dateKey: string, progress: DailyProgress, origin = "https://hidden11.app"): string {
|
||||||
@@ -71,7 +81,7 @@ export function buildShareUrl(dateKey: string, progress: DailyProgress, origin =
|
|||||||
}, {} as Record<Difficulty, ShareDifficultySummary>),
|
}, {} as Record<Difficulty, ShareDifficultySummary>),
|
||||||
};
|
};
|
||||||
|
|
||||||
return `${origin.replace(/\/$/, "")}/result/${encodeSharePayload(payload)}`;
|
return `${origin.replace(/\/$/, "")}/r/${encodeSharePayload(payload)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseSharePayload(shareCode: string): SharePayload | null {
|
export function parseSharePayload(shareCode: string): SharePayload | null {
|
||||||
|
|||||||
Reference in New Issue
Block a user