liveliness + consistency: activity reveal, gatehouse count-up (0.62.0)
- Reveal now accepts a tag prop so it can wrap semantic elements - 'Live in the tavern' activity items stagger-fade-up as they scroll into view (as <li>, valid list semantics), matching the feature cards - gatehouse stats now count up from 0, consistent with the home hero - both respect prefers-reduced-motion - verified live: 8 items reveal (opacity 1, not stuck), gatehouse Count renders, 0 exceptions
This commit is contained in:
parent
2d00cb4e63
commit
e3e5cefd03
@ -4,7 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="theme-color" content="#0e0a14" />
|
<meta name="theme-color" content="#0e0a14" />
|
||||||
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
|
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
|
||||||
<meta name="version" content="0.61.0-syntax" />
|
<meta name="version" content="0.62.0-liveness" />
|
||||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||||
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
|
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "amerc-site",
|
"name": "amerc-site",
|
||||||
"version": "0.61.0-syntax",
|
"version": "0.62.0-liveness",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import Account from './Account.jsx';
|
|||||||
import TavernGame from './TavernGame.jsx';
|
import TavernGame from './TavernGame.jsx';
|
||||||
import { api } from './api.js';
|
import { api } from './api.js';
|
||||||
|
|
||||||
const RELEASE = '0.61.0-syntax';
|
const RELEASE = '0.62.0-liveness';
|
||||||
|
|
||||||
const NAV = [
|
const NAV = [
|
||||||
{ id: 'home', label: 'Tavern' },
|
{ id: 'home', label: 'Tavern' },
|
||||||
@ -86,7 +86,7 @@ function Count({ n }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fade-up as the element scrolls into view; always-visible fallback if no IO / reduced motion.
|
// Fade-up as the element scrolls into view; always-visible fallback if no IO / reduced motion.
|
||||||
function Reveal({ children, className = '', delay = 0 }) {
|
function Reveal({ children, className = '', delay = 0, tag: Tag = 'div' }) {
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
const [armed] = useState(() => typeof window !== 'undefined' && 'IntersectionObserver' in window && !prefersReducedMotion());
|
const [armed] = useState(() => typeof window !== 'undefined' && 'IntersectionObserver' in window && !prefersReducedMotion());
|
||||||
const [shown, setShown] = useState(false);
|
const [shown, setShown] = useState(false);
|
||||||
@ -95,7 +95,7 @@ function Reveal({ children, className = '', delay = 0 }) {
|
|||||||
const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { setShown(true); io.disconnect(); } }); }, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' });
|
const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { setShown(true); io.disconnect(); } }); }, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' });
|
||||||
io.observe(ref.current); return () => io.disconnect();
|
io.observe(ref.current); return () => io.disconnect();
|
||||||
}, [armed]);
|
}, [armed]);
|
||||||
return <div ref={ref} className={`${className} ${armed ? 'reveal' : ''} ${shown ? 'in' : ''}`.replace(/\s+/g, ' ').trim()} style={delay && armed ? { transitionDelay: `${delay}ms` } : undefined}>{children}</div>;
|
return <Tag ref={ref} className={`${className} ${armed ? 'reveal' : ''} ${shown ? 'in' : ''}`.replace(/\s+/g, ' ').trim()} style={delay && armed ? { transitionDelay: `${delay}ms` } : undefined}>{children}</Tag>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Home({ setRoute }) {
|
function Home({ setRoute }) {
|
||||||
@ -149,7 +149,7 @@ function ActivityFeed() {
|
|||||||
<h3 className="hf-sub">Live in the tavern</h3>
|
<h3 className="hf-sub">Live in the tavern</h3>
|
||||||
<ul className="act-list">
|
<ul className="act-list">
|
||||||
{items.map((a, i) => (
|
{items.map((a, i) => (
|
||||||
<li key={i}><span className="act-ico">{ACT_ICON[a.kind] || '•'}</span><span className="act-text">{a.text}</span><span className="act-time">{relTime(a.at)}</span></li>
|
<Reveal tag="li" key={i} delay={Math.min(i, 6) * 50}><span className="act-ico">{ACT_ICON[a.kind] || '•'}</span><span className="act-text">{a.text}</span><span className="act-time">{relTime(a.at)}</span></Reveal>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -309,9 +309,9 @@ function Gatehouse({ auth, setRoute }) {
|
|||||||
<div className="gate-sso"><span>🔓</span> One sign-in works across <b>tavern</b>, <b>docs</b>, <b>PM</b> and <b>git</b>.</div>
|
<div className="gate-sso"><span>🔓</span> One sign-in works across <b>tavern</b>, <b>docs</b>, <b>PM</b> and <b>git</b>.</div>
|
||||||
{stats && (
|
{stats && (
|
||||||
<div className="gate-live">
|
<div className="gate-live">
|
||||||
<span><b>{stats.classes}</b> classes</span><i />
|
<span><b><Count n={stats.classes} /></b> classes</span><i />
|
||||||
<span><b>{stats.online}</b> online</span><i />
|
<span><b><Count n={stats.online} /></b> online</span><i />
|
||||||
<span><b>{stats.sessions}</b> sessions</span>
|
<span><b><Count n={stats.sessions} /></b> sessions</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user