'小红书解析
This commit is contained in:
37
app/components/AddressLink.tsx
Normal file
37
app/components/AddressLink.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
"use client";
|
||||
|
||||
interface AddressLinkProps {
|
||||
place: string;
|
||||
city: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** 可点击的地址,点击打开地图(使用 span 避免嵌套在 Link 内时的 a 标签冲突) */
|
||||
export default function AddressLink({ place, city, className = "" }: AddressLinkProps) {
|
||||
const query = encodeURIComponent(`${city}${place}`);
|
||||
const mapUrl = `https://www.google.com/maps/search/?api=1&query=${query}`;
|
||||
|
||||
return (
|
||||
<span
|
||||
role="link"
|
||||
tabIndex={0}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.open(mapUrl, "_blank", "noopener,noreferrer");
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.open(mapUrl, "_blank", "noopener,noreferrer");
|
||||
}
|
||||
}}
|
||||
className={`inline-flex items-center gap-1 text-stone-500 dark:text-stone-400 hover:text-amber-600 dark:hover:text-amber-400 transition-colors cursor-pointer ${className}`}
|
||||
title="点击打开地图"
|
||||
>
|
||||
<span className="inline-block" aria-hidden>📍</span>
|
||||
{place}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -4,11 +4,12 @@ export default function Footer() {
|
||||
return (
|
||||
<footer className="border-t border-stone-200 dark:border-stone-800 mt-12 py-8">
|
||||
<div className="max-w-[900px] mx-auto px-5 sm:px-8 text-center text-sm text-stone-500 dark:text-stone-400">
|
||||
<div className="flex flex-wrap justify-center gap-x-4 gap-y-1 mb-3">
|
||||
<Link href="/history" className="hover:text-amber-600 dark:hover:text-amber-400">
|
||||
历史活动
|
||||
</Link>
|
||||
</div>
|
||||
<Link
|
||||
href="/join"
|
||||
className="inline-flex items-center gap-1.5 mb-4 text-amber-600 dark:text-amber-400 hover:text-amber-700 dark:hover:text-amber-300 font-medium"
|
||||
>
|
||||
<span aria-hidden>🙋</span> 招募志愿者
|
||||
</Link>
|
||||
<p>© {new Date().getFullYear()} Salon · 深圳 周末轻社交</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -11,9 +11,6 @@ export default function Header() {
|
||||
Salon
|
||||
</Link>
|
||||
<nav className="flex items-center gap-4 sm:gap-6">
|
||||
<Link href="/history" className="text-sm text-stone-600 dark:text-stone-400 hover:text-amber-600 dark:hover:text-amber-400">
|
||||
历史活动
|
||||
</Link>
|
||||
<ThemeToggle />
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import SessionCoverImage from "./SessionCoverImage";
|
||||
import AddressLink from "./AddressLink";
|
||||
import { SESSIONS, RECENT_JOINERS } from "@/config/home.config";
|
||||
|
||||
const MOCK_JOINERS = RECENT_JOINERS.slice(0, 3);
|
||||
@@ -35,7 +36,7 @@ export default function HeroSection() {
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-[2.5rem] xl:text-[2.75rem] font-bold tracking-tight leading-[1.25]">
|
||||
<span className="hero-gradient-text">周末留两小时</span>
|
||||
<br />
|
||||
<span className="text-stone-800 dark:text-stone-100">去loft民宿,认识几位同频的人</span>
|
||||
<span className="text-stone-800 dark:text-stone-100">认识几位同频的人</span>
|
||||
</h1>
|
||||
<p className="mt-4 sm:mt-5 text-stone-600 dark:text-stone-400 text-sm sm:text-base max-w-lg leading-relaxed">
|
||||
深圳 · 6–8 人小圈子
|
||||
@@ -92,7 +93,7 @@ export default function HeroSection() {
|
||||
</p>
|
||||
<h3 className="font-semibold text-stone-800 dark:text-stone-100 text-sm sm:text-base">{mainSession.title}</h3>
|
||||
<p className="text-xs sm:text-sm text-stone-500 dark:text-stone-400 mt-0.5">
|
||||
{mainSession.date} {mainSession.time} · {mainSession.place}
|
||||
{mainSession.date} {mainSession.time} · <AddressLink place={mainSession.place} city={mainSession.city} />
|
||||
</p>
|
||||
<span className="inline-flex items-center gap-1 mt-3 text-amber-600 dark:text-amber-400 font-medium text-xs sm:text-sm">
|
||||
报名这场 →
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import SessionCoverImage from "./SessionCoverImage";
|
||||
import AddressLink from "./AddressLink";
|
||||
import { SESSIONS, ACTIVITY_TYPES, SESSION_TAGS, RECENT_JOINERS } from "@/config/home.config";
|
||||
|
||||
interface JoinStats {
|
||||
@@ -73,7 +74,7 @@ export default function SessionCard({
|
||||
{session.title}
|
||||
</h3>
|
||||
<p className="text-xs sm:text-sm text-stone-500 dark:text-stone-400 mt-0.5">
|
||||
{session.date} {session.time} · {session.place}
|
||||
{session.date} {session.time} · <AddressLink place={session.place} city={session.city} />
|
||||
</p>
|
||||
<span className="inline-flex items-center gap-1 mt-2 sm:mt-3 text-amber-600 dark:text-amber-400 text-xs sm:text-sm font-medium">
|
||||
报名这场 →
|
||||
|
||||
Reference in New Issue
Block a user