feat(proj): init

This commit is contained in:
vl.arkhangelskii
2026-09-21 03:53:15 +03:00
commit 3e34f391b3
258 changed files with 20968 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
import { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { api, type StyleItem } from "../../api";
import { Button, Flash, PageHeader, Section } from "../../components/ui";
import { AppSelect, AppTextField } from "../../ui";
export function StylesPage() {
const navigate = useNavigate();
const [items, setItems] = useState<StyleItem[]>([]);
const [name, setName] = useState("");
const [from, setFrom] = useState("osm-bright");
const [error, setError] = useState<string | null>(null);
const reload = () =>
api
.styles()
.then(setItems)
.catch((err: unknown) => setError(err instanceof Error ? err.message : "Не удалось загрузить стили"));
useEffect(() => {
void reload();
}, []);
const presets = items.filter((item) => item.isPreset);
const cloneFrom = presets.length > 0 ? from : "osm-bright";
return (
<>
<PageHeader
eyebrow="Стили"
title="Карта"
description="Клонируйте пресет и откройте визуальный редактор: слои, карта и свойства."
/>
<Section title="Клонировать пресет">
<div className="form-row">
<AppTextField id="style-name" label="Имя копии" value={name} onChange={(e) => setName(e.target.value)} placeholder="my-bright" />
<AppSelect
id="style-from"
label="Пресет"
value={cloneFrom}
onChange={(e) => setFrom(e.target.value)}
>
{(presets.length > 0 ? presets : [{ name: "osm-bright" }]).map((item) => (
<option key={item.name} value={item.name}>
{item.name}
</option>
))}
</AppSelect>
<Button
variant="primary"
onClick={() => {
setError(null);
void api
.cloneStyle(name, cloneFrom)
.then((created) => navigate(`/styles/${created.name}`))
.catch((err: unknown) => setError(err instanceof Error ? err.message : "Не удалось клонировать"));
}}
>
Клонировать
</Button>
</div>
<Flash error={error} />
</Section>
<Section title="Список">
<table className="data-table">
<thead>
<tr>
<th>Имя</th>
<th>Источник</th>
<th>Тип</th>
</tr>
</thead>
<tbody>
{items.map((item) => (
<tr key={item.name}>
<td>
<Link to={`/styles/${item.name}`}>{item.name}</Link>
</td>
<td>{item.createdFrom ?? "—"}</td>
<td>{item.isPreset ? "пресет" : "мой"}</td>
</tr>
))}
</tbody>
</table>
</Section>
</>
);
}