Spaces for Purchase List
This commit is contained in:
+101
@@ -251,6 +251,36 @@
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.spaces-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.space-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
padding: 0.5rem 0.9rem;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.space-tag::before {
|
||||
content: "@";
|
||||
color: var(--brand-light);
|
||||
margin-right: 0.05rem;
|
||||
}
|
||||
|
||||
.spaces-status {
|
||||
margin: 0 0 1.25rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
padding: 2.5rem 0 3rem;
|
||||
@@ -374,6 +404,17 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="spaces">
|
||||
<div class="wrap">
|
||||
<h2>Spaces available in SpacesWallet</h2>
|
||||
<p class="section-lead">
|
||||
Active @spaces currently listed for discovery and purchase in the app.
|
||||
</p>
|
||||
<p class="spaces-status" id="spaces-status">Loading live listings…</p>
|
||||
<div class="spaces-list" id="spaces-list" aria-live="polite"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="wrap">
|
||||
<h2>Built for crypto natives</h2>
|
||||
@@ -423,5 +464,65 @@
|
||||
<p>© 2026 Lunde Cognitive Effects Inc.</p>
|
||||
</div>
|
||||
</footer>
|
||||
<script>
|
||||
const SPACES_ENDPOINTS = [
|
||||
"/api/spaces",
|
||||
"https://spacesops.com/getspaces?app=spaces-wallet&format=json"
|
||||
];
|
||||
const FALLBACK_SPACES = [
|
||||
"space", "tabconf", "bitvocation", "nsite", "yeti", "ungovernable",
|
||||
"bitcoinand", "thisweekinbitcoin", "twib", "imagineif", "acorn",
|
||||
"bitcoin21", "usdt", "usat", "cnht", "mxnt", "xaut", "usdc", "eurc",
|
||||
"zap", "pubkey", "cyber", "swifty", "heart"
|
||||
];
|
||||
|
||||
function renderSpaces(names, sourceLabel) {
|
||||
const list = document.getElementById("spaces-list");
|
||||
const status = document.getElementById("spaces-status");
|
||||
list.replaceChildren();
|
||||
names.forEach((name) => {
|
||||
const tag = document.createElement("span");
|
||||
tag.className = "space-tag";
|
||||
tag.textContent = name;
|
||||
list.appendChild(tag);
|
||||
});
|
||||
status.textContent = names.length + " active spaces · " + sourceLabel;
|
||||
}
|
||||
|
||||
function namesFromPayload(data) {
|
||||
if (!data || !Array.isArray(data.spaces)) return [];
|
||||
return data.spaces
|
||||
.slice()
|
||||
.sort((a, b) => (a.show_order || 0) - (b.show_order || 0))
|
||||
.map((space) => space.space_name)
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function freshUrl(url) {
|
||||
return url + (url.includes("?") ? "&" : "?") + "t=" + Date.now();
|
||||
}
|
||||
|
||||
async function loadSpaces() {
|
||||
const status = document.getElementById("spaces-status");
|
||||
status.textContent = "Refreshing listings…";
|
||||
|
||||
for (const url of SPACES_ENDPOINTS) {
|
||||
try {
|
||||
const response = await fetch(freshUrl(url), { cache: "no-store" });
|
||||
if (!response.ok) continue;
|
||||
const names = namesFromPayload(await response.json());
|
||||
if (names.length) {
|
||||
renderSpaces(names, "updated just now");
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
// Try the next endpoint or fall back to the last known list.
|
||||
}
|
||||
}
|
||||
renderSpaces(FALLBACK_SPACES, "last known listings");
|
||||
}
|
||||
|
||||
window.addEventListener("pageshow", loadSpaces);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user