Implementing API - WIP frontend
This commit is contained in:
+230
-5
@@ -8,11 +8,102 @@
|
||||
body {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
height: 100%;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#map-container {
|
||||
grid-column: 1 / 2;
|
||||
grid-row: 1 / 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
margin: auto;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#file-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
#plan-container {
|
||||
grid-column: 2 / 3;
|
||||
grid-row: 1 / 2;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
#file-content h1,
|
||||
#file-content h2,
|
||||
#file-content h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#file-content p {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.plan-item {
|
||||
background: white;
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.plan-item h4 {
|
||||
margin: 0 0 8px 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-to-plan-btn {
|
||||
background: #6d4aff;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.add-to-plan-btn:hover {
|
||||
background: #5a3fd6;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 32px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/node_modules/leaflet/dist/leaflet.css" />
|
||||
@@ -29,10 +120,144 @@
|
||||
<script src="graph.mjs" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
import {Graph} from "./graph.mjs"
|
||||
<div class="container">
|
||||
<div id="map-container">
|
||||
<div id="map"></div>
|
||||
<div id="file-content">
|
||||
<div class="empty-state">Click on a destination marker to view details</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="plan-container">
|
||||
<h3>My Plan</h3>
|
||||
<div id="plan-items">
|
||||
<div class="empty-state">No destinations added yet</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script defer type="module">
|
||||
import {Graph} from "./graph.mjs";
|
||||
|
||||
const planItems = [];
|
||||
|
||||
function displayContent(data) {
|
||||
const contentDiv = document.getElementById("file-content");
|
||||
|
||||
if (!data || !data.Content) {
|
||||
contentDiv.innerHTML = '<div class="empty-state">No content available</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = "";
|
||||
|
||||
// Show global content first if available
|
||||
if (data.Content.global) {
|
||||
html += `<h1>${data.Content.global.Title || "Untitled"}</h1>`;
|
||||
for (const [section, subsections] of Object.entries(data.Content.global)) {
|
||||
if (section === "Title") continue;
|
||||
html += `<h2>${section}</h2>`;
|
||||
if (typeof subsections === "object") {
|
||||
for (const [sub, content] of Object.entries(subsections)) {
|
||||
html += `<h3>${sub}</h3><p>${content}</p>`;
|
||||
}
|
||||
} else {
|
||||
html += `<p>${subsections}</p>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show language-specific content
|
||||
for (const [lang, content] of Object.entries(data.Content)) {
|
||||
if (lang === "global") continue;
|
||||
|
||||
html += `<h2>${lang}</h2>`;
|
||||
if (content.Title) {
|
||||
html += `<h1>${content.Title}</h1>`;
|
||||
}
|
||||
|
||||
for (const [section, subsections] of Object.entries(content)) {
|
||||
if (section === "Title") continue;
|
||||
html += `<h3>${section}</h3>`;
|
||||
if (typeof subsections === "object") {
|
||||
for (const [sub, text] of Object.entries(subsections)) {
|
||||
html += `<h4>${sub}</h4><p>${text}</p>`;
|
||||
}
|
||||
} else {
|
||||
html += `<p>${subsections}</p>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add "Add to Plan" button
|
||||
const ref = data.Reference?.reference || "unknown";
|
||||
const name =
|
||||
data.Content?.global?.Title ||
|
||||
Object.values(data.Content)?.[0]?.Title ||
|
||||
"Destination";
|
||||
|
||||
html += `
|
||||
<button class="add-to-plan-btn" onclick="addToPlan('${ref}', '${name}')">
|
||||
Add to Plan
|
||||
</button>
|
||||
`;
|
||||
|
||||
contentDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
window.addToPlan = function (ref, name) {
|
||||
if (planItems.some(item => item.ref === ref)) {
|
||||
alert("Already in plan!");
|
||||
return;
|
||||
}
|
||||
|
||||
planItems.push({ref, name});
|
||||
updatePlanDisplay();
|
||||
};
|
||||
|
||||
function updatePlanDisplay() {
|
||||
const planDiv = document.getElementById("plan-items");
|
||||
|
||||
if (planItems.length === 0) {
|
||||
planDiv.innerHTML = '<div class="empty-state">No destinations added yet</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = "";
|
||||
for (const item of planItems) {
|
||||
html += `
|
||||
<div class="plan-item">
|
||||
<h4>${item.name}</h4>
|
||||
<small>${item.ref}</small>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
planDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const network = new Graph();
|
||||
|
||||
// Override the click handler to display content instead of loading connected pins
|
||||
const originalGet = network.get.bind(network);
|
||||
|
||||
network.get = async function (ref) {
|
||||
const element = await originalGet(ref);
|
||||
|
||||
// If this is a node (destination), display its content
|
||||
if (element && element.data && element.data.Content) {
|
||||
displayContent(element.data);
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
// Also override the Node.draw method to use our custom click handler
|
||||
const originalNodeDraw = network.nodesConstructor
|
||||
? network.nodesConstructor.prototype.draw
|
||||
: null;
|
||||
|
||||
// Reinitialize with our custom behavior
|
||||
const t = await network.get("<NO/Lunde>");
|
||||
network.draw();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user