You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
7.9 KiB
HTML
318 lines
7.9 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Leaflet Components Demo</title>
|
|
<style>
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0;
|
|
padding: 20px;
|
|
font-family: sans-serif;
|
|
}
|
|
.two-pane {
|
|
display: flex;
|
|
gap: 16px;
|
|
margin-bottom: 16px;
|
|
height: 600px;
|
|
}
|
|
.pane {
|
|
border: 1px solid #ddd;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.pane-header {
|
|
padding: 10px 14px;
|
|
font-weight: 600;
|
|
font-size: 13px;
|
|
background: #f0f0f0;
|
|
border-bottom: 1px solid #ddd;
|
|
flex-shrink: 0;
|
|
}
|
|
.pane-body {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 10px 14px;
|
|
}
|
|
#tree-pane {
|
|
width: 280px;
|
|
min-width: 200px;
|
|
}
|
|
#editor-pane {
|
|
flex: 1;
|
|
min-width: 300px;
|
|
}
|
|
|
|
/* ── Tree styles ── */
|
|
.tree-node {
|
|
margin: 2px 0;
|
|
}
|
|
.tree-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 4px 6px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-family: monospace;
|
|
font-size: 13px;
|
|
}
|
|
.tree-row:hover {
|
|
background: #e8e8e8;
|
|
}
|
|
.tree-row.selected {
|
|
background: #dbeafe;
|
|
font-weight: 600;
|
|
}
|
|
.tree-row .tag {
|
|
color: #2563eb;
|
|
}
|
|
.tree-children {
|
|
margin-left: 18px;
|
|
border-left: 1px solid #ddd;
|
|
padding-left: 4px;
|
|
}
|
|
.tree-row .remove-btn {
|
|
margin-left: auto;
|
|
background: none;
|
|
border: none;
|
|
color: #999;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
line-height: 1;
|
|
padding: 0 2px;
|
|
}
|
|
.tree-row .remove-btn:hover {
|
|
color: #dc2626;
|
|
}
|
|
.tree-row .add-child-btn {
|
|
background: none;
|
|
border: none;
|
|
color: #999;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
line-height: 1;
|
|
padding: 0 2px;
|
|
margin: 0 0 0 4px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.tree-row .add-child-btn:hover {
|
|
color: #22c55e;
|
|
}
|
|
.add-child-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
margin-top: 6px;
|
|
padding: 4px 10px;
|
|
font-size: 12px;
|
|
border: 1px dashed #aaa;
|
|
border-radius: 4px;
|
|
background: none;
|
|
color: #666;
|
|
cursor: pointer;
|
|
}
|
|
.add-child-btn:hover {
|
|
border-color: #3b82f6;
|
|
color: #2563eb;
|
|
}
|
|
|
|
/* ── Editor styles ── */
|
|
.editor-empty {
|
|
color: #999;
|
|
font-style: italic;
|
|
font-size: 13px;
|
|
}
|
|
.editor-section {
|
|
margin-bottom: 14px;
|
|
}
|
|
.editor-section h4 {
|
|
margin: 0 0 8px;
|
|
font-size: 11px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
color: #888;
|
|
}
|
|
.editor-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 6px;
|
|
}
|
|
.editor-row label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-size: 13px;
|
|
color: #555;
|
|
min-width: 120px;
|
|
}
|
|
.editor-row label:has(input[type="checkbox"]) {
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
min-width: auto;
|
|
}
|
|
.editor-row input[type="number"],
|
|
.editor-row input[type="text"] {
|
|
flex: 1;
|
|
max-width: 200px;
|
|
padding: 5px 8px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-size: 13px;
|
|
font-family: monospace;
|
|
}
|
|
.editor-row input:focus {
|
|
outline: none;
|
|
border-color: #66f;
|
|
}
|
|
.editor-row input[type="checkbox"] {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
.pick-btn {
|
|
padding: 4px 8px;
|
|
font-size: 11px;
|
|
border: 1px solid #22c55e;
|
|
border-radius: 4px;
|
|
background: #f0fdf4;
|
|
color: #16a34a;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
.pick-btn:hover {
|
|
background: #dcfce7;
|
|
}
|
|
.pick-btn.picking {
|
|
background: #16a34a;
|
|
color: white;
|
|
animation: pulse 1s infinite;
|
|
}
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.7; }
|
|
}
|
|
|
|
/* ── Add-child modal ── */
|
|
.add-child-form {
|
|
margin-top: 10px;
|
|
padding: 10px;
|
|
background: #fafafa;
|
|
border: 1px solid #ddd;
|
|
border-radius: 6px;
|
|
}
|
|
.add-child-form h5 {
|
|
margin: 0 0 8px;
|
|
font-size: 12px;
|
|
color: #555;
|
|
}
|
|
.add-child-form select,
|
|
.add-child-form input {
|
|
width: 100%;
|
|
padding: 5px 8px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-size: 13px;
|
|
margin-bottom: 6px;
|
|
}
|
|
.add-child-form .form-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-top: 8px;
|
|
}
|
|
.add-child-form button {
|
|
padding: 6px 14px;
|
|
border-radius: 4px;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
border: 1px solid #ccc;
|
|
background: white;
|
|
}
|
|
.add-child-form button.primary {
|
|
background: #2563eb;
|
|
color: white;
|
|
border-color: #2563eb;
|
|
}
|
|
.add-child-form button.primary:hover {
|
|
background: #1d4ed8;
|
|
}
|
|
.add-child-form button.cancel {
|
|
background: #f5f5f5;
|
|
}
|
|
|
|
leaflet-map {
|
|
height: 500px;
|
|
border: 1px solid #ccc;
|
|
display: block;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Leaflet Web Components</h1>
|
|
|
|
<leaflet-map id="map" lat="51.50" lng="-0.09" zoom="13">
|
|
<leaflet-tile-layer
|
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
attribution="© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
|
|
>
|
|
</leaflet-tile-layer>
|
|
|
|
<leaflet-marker lat="51.5" lng="-0.09">
|
|
<leaflet-icon
|
|
icon-url="https://leafletjs.com/examples/custom-icons/leaf-green.png"
|
|
icon-anchor="[22, 94]"
|
|
icon-size="[38, 95]"
|
|
popup-anchor="[-3, -76]"
|
|
shadow-url="https://leafletjs.com/examples/custom-icons/leaf-shadow.png"
|
|
shadow-anchor="[4, 62]"
|
|
shadow-size="[50, 64]"
|
|
></leaflet-icon>
|
|
<leaflet-popup>I am a green leaf.</leaflet-popup>
|
|
</leaflet-marker>
|
|
|
|
<leaflet-marker lat="51.495" lng="-0.083">
|
|
<leaflet-icon
|
|
icon-url="https://leafletjs.com/examples/custom-icons/leaf-red.png"
|
|
icon-anchor="[22, 94]"
|
|
icon-size="[38, 95]"
|
|
popup-anchor="[-3, -76]"
|
|
shadow-anchor="[4, 62]"
|
|
shadow-size="[50, 64]"
|
|
shadow-url="https://leafletjs.com/examples/custom-icons/leaf-shadow.png"
|
|
></leaflet-icon>
|
|
<leaflet-popup>I am a red leaf.</leaflet-popup>
|
|
</leaflet-marker>
|
|
|
|
<leaflet-marker lat="51.49" lng="-0.1">
|
|
<leaflet-icon
|
|
icon-url="https://leafletjs.com/examples/custom-icons/leaf-orange.png"
|
|
icon-anchor="[22, 94]"
|
|
icon-size="[38, 95]"
|
|
shadow-url="https://leafletjs.com/examples/custom-icons/leaf-shadow.png"
|
|
popup-anchor="[-3, -76]"
|
|
shadow-anchor="[4, 62]"
|
|
shadow-size="[50, 64]"
|
|
></leaflet-icon>
|
|
<leaflet-popup>I am a orange leaf.</leaflet-popup>
|
|
</leaflet-marker>
|
|
</leaflet-map>
|
|
|
|
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"leaflet": "/node_modules/leaflet/dist/leaflet-src.esm.js"
|
|
}
|
|
}
|
|
</script>
|
|
<script type="module" src="/dist/index.js"></script>
|
|
<script type="module">
|
|
</script>
|
|
</body>
|
|
</html>
|