// portal-sections.jsx — Nav, Hero, Districts, Zoo, Footer
function Nav() {
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 60);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
return (
);
}
function HeroSlideshow() {
const [images, setImages] = React.useState(null); // null=読込中, []=画像なし
const [idx, setIdx] = React.useState(0);
const timer = React.useRef(null);
const INTERVAL = 5500;
// images/ フォルダの一覧を取得(フォルダの増減に自動対応)
React.useEffect(() => {
let alive = true;
fetch("images_api.php", { credentials: "same-origin" })
.then(r => r.ok ? r.json() : Promise.reject())
.then(d => { if (alive) setImages(Array.isArray(d.images) ? d.images : []); })
.catch(() => { if (alive) setImages([]); });
return () => { alive = false; };
}, []);
const count = images ? images.length : 0;
// 自動再生
React.useEffect(() => {
if (count <= 1) return;
timer.current = setInterval(() => setIdx(i => (i + 1) % count), INTERVAL);
return () => clearInterval(timer.current);
}, [count]);
const go = (n) => {
setIdx((n + count) % count);
if (timer.current) { clearInterval(timer.current); }
if (count > 1) timer.current = setInterval(() => setIdx(i => (i + 1) % count), INTERVAL);
};
// 画像が無い / 読込中は、従来のイラスト背景を表示
if (!images || count === 0) {
return
;
}
return (
{images.map((src, i) => (
))}
{count > 1 && (
<>
{images.map((_, i) => (
>
)}
);
}
function Hero() {
return (
安
佐
町
EST. 1955 ─ HIROSHIMA
広島市 安佐北区 ─ HIROSHIMA CITY · ASAKITA-KU
ふるさとは、
少し遠く。
広島の北、太田川と十の地区が、川と山と人でつながる町。
季節とともに、ゆっくり生きるための場所があります。
{DISTRICTS.map((d, i) => (
{d.name}
{d.ro}
{i < DISTRICTS.length - 1 && ·}
))}
+ 安佐動物公園
34°35′N · 132°27′E · 125.1 KM²
);
}
function DistrictsStrip() {
return (
02 ─ TEN DISTRICTS
十の地区Ten Districts, One Town
飯室・鈴張・久地・久地南・小河内・毛木・後山・宮野・筒瀬・あさひが丘。それぞれの風土を育んできた十の地区が、太田川と里山に抱かれて連なります。
{DISTRICTS.map(d => (
{d.idx}
{d.name}
{d.ro}
{d.pop && d.pop !== "—" && (
人口{d.pop}
)}
特徴{d.feat}
))}
);
}
function ZooSlideshow() {
const [images, setImages] = React.useState(null); // null=読込中, []=画像なし
const [idx, setIdx] = React.useState(0);
const timer = React.useRef(null);
const INTERVAL = 5000;
// asazoo/ フォルダの一覧を取得(フォルダの増減に自動対応)
React.useEffect(() => {
let alive = true;
fetch("asazoo_api.php", { credentials: "same-origin" })
.then(r => r.ok ? r.json() : Promise.reject())
.then(d => { if (alive) setImages(Array.isArray(d.images) ? d.images : []); })
.catch(() => { if (alive) setImages([]); });
return () => { alive = false; };
}, []);
const count = images ? images.length : 0;
React.useEffect(() => {
if (count <= 1) return;
timer.current = setInterval(() => setIdx(i => (i + 1) % count), INTERVAL);
return () => clearInterval(timer.current);
}, [count]);
const go = (n) => {
setIdx((n + count) % count);
if (timer.current) clearInterval(timer.current);
if (count > 1) timer.current = setInterval(() => setIdx(i => (i + 1) % count), INTERVAL);
};
// 画像が無い / 読込中は、従来のプレースホルダ(獸+足跡)を表示
if (!images || count === 0) {
return (
<>
獸
>
);
}
return (
{images.map((src, i) => (
))}
{count > 1 && (
<>
{images.map((_, i) => (
>
)}
);
}
function ZooSection() {
return (
03 ─ ICONIC SPOT
安佐動物公園Asa Zoological Park · since 1971
日浦の丘陵地に広がる、広島市民の動物園。アフリカからやってきたキリンやサイ、希少なツキノワグマまで、約160種・1700頭羽が暮らしています。安佐町の里山に開かれた、季節を映す動物園。
);
}
function Footer({ toast }) {
return (
);
}
Object.assign(window, { Nav, Hero, DistrictsStrip, ZooSection, Footer });