feat: 首页支持宣传语
This commit is contained in:
@@ -7,6 +7,7 @@ import { Globe, Map } from "lucide-react";
|
||||
import { Navbar } from "@/components/layout/navbar";
|
||||
import { InstallBanner } from "@/components/layout/install-banner";
|
||||
import { ParticleBg } from "@/components/layout/particle-bg";
|
||||
import { Hero } from "@/components/layout/hero";
|
||||
import { GlobeView } from "@/components/globe/globe-view";
|
||||
import { StatsPanel } from "@/components/dashboard/stats-panel";
|
||||
import { ActivityTimeline } from "@/components/dashboard/activity-timeline";
|
||||
@@ -45,6 +46,9 @@ export default function HomePage() {
|
||||
<Navbar />
|
||||
|
||||
<main className="relative z-10 mx-auto max-w-[1800px] px-4 pt-20 pb-8">
|
||||
{/* Hero Section */}
|
||||
<Hero />
|
||||
|
||||
{/* Section 1: Main Map View + Dashboard */}
|
||||
<section className="min-h-[calc(100vh-5rem)]">
|
||||
<div className="mb-4">
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
incrementHourlyActivity,
|
||||
publishEvent,
|
||||
} from "@/lib/redis";
|
||||
import { validateApiKey } from "@/lib/auth/api-key";
|
||||
import { authenticateRequest } from "@/lib/auth/request";
|
||||
import { getGeoLocation } from "@/lib/geo/ip-location";
|
||||
import { heartbeatSchema } from "@/lib/validators/schemas";
|
||||
|
||||
@@ -22,19 +22,11 @@ function getClientIp(req: NextRequest): string {
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (!authHeader?.startsWith("Bearer ")) {
|
||||
return NextResponse.json(
|
||||
{ error: "Missing or invalid authorization header" },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const apiKey = authHeader.slice(7);
|
||||
const claw = await validateApiKey(apiKey);
|
||||
if (!claw) {
|
||||
return NextResponse.json({ error: "Invalid API key" }, { status: 401 });
|
||||
const auth = await authenticateRequest(req);
|
||||
if (auth instanceof NextResponse) {
|
||||
return auth;
|
||||
}
|
||||
const { claw } = auth;
|
||||
|
||||
let bodyData = {};
|
||||
try {
|
||||
|
||||
@@ -7,24 +7,16 @@ import {
|
||||
incrementHourlyActivity,
|
||||
publishEvent,
|
||||
} from "@/lib/redis";
|
||||
import { validateApiKey } from "@/lib/auth/api-key";
|
||||
import { authenticateRequest } from "@/lib/auth/request";
|
||||
import { taskSchema } from "@/lib/validators/schemas";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (!authHeader?.startsWith("Bearer ")) {
|
||||
return NextResponse.json(
|
||||
{ error: "Missing or invalid authorization header" },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const apiKey = authHeader.slice(7);
|
||||
const claw = await validateApiKey(apiKey);
|
||||
if (!claw) {
|
||||
return NextResponse.json({ error: "Invalid API key" }, { status: 401 });
|
||||
const auth = await authenticateRequest(req);
|
||||
if (auth instanceof NextResponse) {
|
||||
return auth;
|
||||
}
|
||||
const { claw } = auth;
|
||||
|
||||
const body = await req.json();
|
||||
const parsed = taskSchema.safeParse(body);
|
||||
|
||||
@@ -2,7 +2,8 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { db } from "@/lib/db";
|
||||
import { invalidateTokenLeaderboardCache } from "@/lib/redis";
|
||||
import { authenticateRequest, getTodayDateString } from "@/lib/utils";
|
||||
import { authenticateRequest } from "@/lib/auth/request";
|
||||
import { getTodayDateString } from "@/lib/utils";
|
||||
import { tokenSchema } from "@/lib/validators/schemas";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
|
||||
@@ -2,7 +2,8 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { eq, and, gte, sql } from "drizzle-orm";
|
||||
import { db } from "@/lib/db";
|
||||
import { tokenUsage } from "@/lib/db/schema";
|
||||
import { authenticateRequest, getTodayDateString } from "@/lib/utils";
|
||||
import { authenticateRequest } from "@/lib/auth/request";
|
||||
import { getTodayDateString } from "@/lib/utils";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
|
||||
@@ -171,3 +171,80 @@ body {
|
||||
.maplibre-dark-popup .maplibregl-popup-close-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* === Hero Animations === */
|
||||
|
||||
/* Fade in animation */
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fade in and slide up animation */
|
||||
@keyframes fade-in-up {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Glowing text pulse animation */
|
||||
@keyframes glow-pulse {
|
||||
0%, 100% {
|
||||
text-shadow:
|
||||
0 0 10px rgba(0, 240, 255, 0.5),
|
||||
0 0 20px rgba(0, 240, 255, 0.3),
|
||||
0 0 40px rgba(0, 240, 255, 0.1);
|
||||
}
|
||||
50% {
|
||||
text-shadow:
|
||||
0 0 15px rgba(0, 240, 255, 0.6),
|
||||
0 0 30px rgba(0, 240, 255, 0.4),
|
||||
0 0 60px rgba(0, 240, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation utility classes */
|
||||
.animate-fade-in {
|
||||
animation: fade-in 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
.animate-fade-in-up {
|
||||
animation: fade-in-up 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
/* Glowing text with pulse effect */
|
||||
.glow-text-pulse {
|
||||
color: var(--text-primary);
|
||||
animation: glow-pulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Animation delays */
|
||||
.animation-delay-200 {
|
||||
animation-delay: 0.2s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.animation-delay-400 {
|
||||
animation-delay: 0.4s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Accessibility: Respect reduced motion preferences */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.animate-fade-in,
|
||||
.animate-fade-in-up,
|
||||
.glow-text-pulse {
|
||||
animation: none;
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user