tons of feature
This commit is contained in:
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
26
app/globals.css
Normal file
26
app/globals.css
Normal file
@@ -0,0 +1,26 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
34
app/layout.tsx
Normal file
34
app/layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
86
app/page.tsx
Normal file
86
app/page.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import Map from "@/components/Map";
|
||||
import Editor from "@/components/Editor";
|
||||
import {
|
||||
FeatureCollection,
|
||||
useEditorState,
|
||||
} from "@/lib/useEditorState";
|
||||
|
||||
const EMPTY_FC: FeatureCollection = { type: "FeatureCollection", features: [] };
|
||||
|
||||
export default function Page() {
|
||||
const [mode, setMode] = useState<"idle" | "draw" | "select" | "add-point">("idle");
|
||||
const [initialData, setInitialData] = useState<FeatureCollection>(EMPTY_FC);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const editor = useEditorState(initialData);
|
||||
|
||||
useEffect(() => {
|
||||
async function loadInitial() {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
minLng: "-180",
|
||||
minLat: "-90",
|
||||
maxLng: "180",
|
||||
maxLat: "90",
|
||||
});
|
||||
|
||||
const res = await fetch(`http://localhost:3000/geometries?${params.toString()}`);
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
setInitialData(data);
|
||||
} catch (err) {
|
||||
console.error("Load initial data failed", err);
|
||||
}
|
||||
}
|
||||
|
||||
loadInitial();
|
||||
}, []);
|
||||
|
||||
const handleSave = async () => {
|
||||
const payload = editor.buildPayload();
|
||||
if (!payload.length) return;
|
||||
setIsSaving(true);
|
||||
try {
|
||||
const res = await fetch("http://localhost:3000/geometries/batch", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ changes: payload }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
console.error("Save failed", text);
|
||||
return;
|
||||
}
|
||||
editor.clearChanges();
|
||||
} catch (err) {
|
||||
console.error("Save error", err);
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Editor
|
||||
mode={mode}
|
||||
setMode={setMode}
|
||||
onUndo={editor.undo}
|
||||
onSave={handleSave}
|
||||
isSaving={isSaving}
|
||||
changesCount={editor.changeCount}
|
||||
undoStack={editor.undoStack}
|
||||
/>
|
||||
|
||||
<Map
|
||||
mode={mode}
|
||||
draft={editor.draft}
|
||||
onCreateFeature={editor.createFeature}
|
||||
onDeleteFeature={editor.deleteFeature}
|
||||
onUpdateFeature={editor.updateFeature}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user