mirror of
https://github.com/tiennm99/vngeoguessr.git
synced 2026-10-11 03:13:56 +00:00
feat(footer): link the build sha to its commit page
The sha now opens that commit on GitHub in a new tab, and a copy button beside it takes over copying the full value.
This commit is contained in:
1 parent
7862bcec9d
commit
6251ea5f4b
1 file changed
+48
-19
@@ -2,14 +2,18 @@
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
// Where the sha links to. Hard-coded rather than derived from a git remote:
|
||||
// the remote is a build-machine detail, the public repo is a product fact.
|
||||
const REPO_URL = 'https://github.com/tiennm99/vngeoguessr';
|
||||
|
||||
// Footer credit plus build stamp, rendered on every page: who made this, and
|
||||
// which commit is this deployment?
|
||||
//
|
||||
// An in-flow strip at the bottom of the body's sticky-footer column, not a
|
||||
// fixed overlay: it owns its own row (and the home-indicator safe area), so
|
||||
// it never overlaps the game's panorama, map, or action bar, and no layer
|
||||
// needs a z-index to win over it. Clicking the sha copies the FULL value
|
||||
// (the label shows the short form).
|
||||
// needs a z-index to win over it. The sha label opens that commit on GitHub;
|
||||
// the button beside it copies the FULL sha (the label shows the short form).
|
||||
//
|
||||
// Height is --footer-h (36px) rather than the 44px touch floor: this strip is
|
||||
// a band taken out of the game's non-scrolling surface, where in landscape
|
||||
@@ -17,6 +21,7 @@ import { useEffect, useRef, useState } from 'react';
|
||||
// minimum, and both targets stay wide.
|
||||
export default function DebugFooter() {
|
||||
const sha = process.env.NEXT_PUBLIC_COMMIT_SHA || 'unknown';
|
||||
const hasSha = sha !== 'unknown';
|
||||
const [copied, setCopied] = useState(false);
|
||||
const resetTimerRef = useRef(null);
|
||||
|
||||
@@ -35,34 +40,58 @@ export default function DebugFooter() {
|
||||
}
|
||||
};
|
||||
|
||||
// Every footer target shares this: --footer-h tall so the tap area comes
|
||||
// from padding rather than the deliberately tiny label. Horizontal padding
|
||||
// is per-target, so the sha and its copy button can sit tight together
|
||||
// while each still spans the full strip height.
|
||||
const targetClass =
|
||||
'flex min-h-(--footer-h) items-center justify-center rounded-md text-[11px] leading-none text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring';
|
||||
|
||||
return (
|
||||
<footer className="flex shrink-0 items-center justify-center gap-2 border-t border-border bg-card pb-[env(safe-area-inset-bottom)]">
|
||||
<footer className="flex shrink-0 items-center justify-center gap-1 border-t border-border bg-card pb-[env(safe-area-inset-bottom)]">
|
||||
<a
|
||||
href="https://miti99.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex min-h-(--footer-h) items-center rounded-md px-3 text-[11px] leading-none text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring"
|
||||
className={`${targetClass} px-3`}
|
||||
>
|
||||
Made by <span className="underline underline-offset-2 mx-1">miti99</span> with{' '}
|
||||
<span aria-hidden="true" className="ml-1">❤️</span>
|
||||
<span className="sr-only">love</span>
|
||||
</a>
|
||||
<span className="text-[11px] leading-none text-muted-foreground" aria-hidden="true">·</span>
|
||||
{/* The visual is deliberately tiny, so the tap target comes from
|
||||
padding: --footer-h tall, well past the label's own box. min-w in ch
|
||||
keeps the width stable when the 7-char sha swaps for the 7-char
|
||||
'copied!', so the click never shifts the thing being clicked.
|
||||
aria-live announces that swap to screen readers. */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopy}
|
||||
aria-label="Copy build commit"
|
||||
aria-live="polite"
|
||||
title={sha}
|
||||
className="flex min-h-(--footer-h) min-w-[9ch] cursor-pointer select-none items-center justify-center rounded-md px-3 font-mono text-[11px] leading-none text-muted-foreground underline underline-offset-2 transition-colors hover:text-foreground active:text-foreground focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring"
|
||||
>
|
||||
{copied ? 'copied!' : sha.slice(0, 7)}
|
||||
</button>
|
||||
{/* The sha and its copy button read as one control, so they sit in a
|
||||
gapless pair rather than as two separate items in the footer row. */}
|
||||
<span className="flex items-center">
|
||||
{hasSha ? (
|
||||
<a
|
||||
href={`${REPO_URL}/commit/${sha}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title={sha}
|
||||
aria-label={`View build commit ${sha} on GitHub`}
|
||||
className={`${targetClass} pl-2 pr-1 font-mono underline underline-offset-2`}
|
||||
>
|
||||
{sha.slice(0, 7)}
|
||||
</a>
|
||||
) : (
|
||||
<span className={`${targetClass} px-2 font-mono`}>{sha}</span>
|
||||
)}
|
||||
{/* aria-live announces the ✅ swap; the emoji itself is decorative, so
|
||||
the label carries the meaning either way. */}
|
||||
{hasSha && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopy}
|
||||
aria-label={copied ? 'Build commit copied' : 'Copy build commit'}
|
||||
aria-live="polite"
|
||||
title="Copy full commit sha"
|
||||
className={`${targetClass} cursor-pointer select-none pl-1 pr-2 active:text-foreground`}
|
||||
>
|
||||
<span aria-hidden="true">{copied ? '✅' : '🗐'}</span>
|
||||
</button>
|
||||
)}
|
||||
</span>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user