nomadweb/frontend/src/components/CityNotes.tsx
eric 04f8c14ed5 Add power plugs, emergency contacts, city notes, and focus timer
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-29 00:18:39 -05:00

95 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useEffect, useState } from "react";
import { useToast } from "@/lib/toast";
import type { Destination } from "@/lib/types";
const STORAGE_KEY = "nomadro-city-notes";
interface Props {
destinations: Destination[];
}
export default function CityNotes({ destinations }: Props) {
const { toast } = useToast();
const [slug, setSlug] = useState(destinations[0]?.slug || "bali");
const [notes, setNotes] = useState<Record<string, string>>({});
const [text, setText] = useState("");
const [ready, setReady] = useState(false);
const dest = destinations.find((d) => d.slug === slug);
useEffect(() => {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) setNotes(JSON.parse(raw));
} catch { /* ignore */ }
setReady(true);
}, []);
useEffect(() => {
if (!ready) return;
setText(notes[slug] || "");
}, [slug, notes, ready]);
const save = () => {
const next = { ...notes, [slug]: text };
setNotes(next);
localStorage.setItem(STORAGE_KEY, JSON.stringify(next));
toast(`${dest?.emoji || ""} 笔记已保存`);
};
const clear = () => {
const next = { ...notes };
delete next[slug];
setNotes(next);
setText("");
localStorage.setItem(STORAGE_KEY, JSON.stringify(next));
toast("已清空该城笔记", "info");
};
const filled = Object.keys(notes).filter((k) => notes[k]?.trim()).length;
return (
<section className="section notes-section" id="notes">
<div className="container">
<div className="section-header reveal">
<span className="section-tag">📝 NOTES</span>
<h2>城市旅居笔记</h2>
<p>记录咖啡馆坐标、房东微信、避坑心得——只存在你的浏览器里</p>
</div>
<div className="notes-card reveal">
<div className="notes-sidebar">
{destinations.map((d) => (
<button
key={d.slug}
className={`notes-city${slug === d.slug ? " active" : ""}`}
onClick={() => setSlug(d.slug)}
>
<span>{d.emoji} {d.name}</span>
{notes[d.slug]?.trim() && <span className="notes-dot" />}
</button>
))}
<p className="notes-count">已记录 {filled} 座城市</p>
</div>
<div className="notes-editor">
<h3>{dest?.emoji} {dest?.name}</h3>
<textarea
className="notes-textarea"
rows={10}
placeholder={`写下关于 ${dest?.name || "这座城"} 的笔记…\n例如:好用的咖啡馆、长租价格、避坑提醒`}
value={text}
onChange={(e) => setText(e.target.value)}
/>
<div className="notes-actions">
<button className="btn btn-primary" onClick={save}>💾 保存</button>
<button className="btn btn-ghost" onClick={clear} disabled={!text.trim()}>清空</button>
</div>
</div>
</div>
</div>
</section>
);
}