Spaces for Purchase List
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
module.exports = async function handler(req, res) {
|
||||||
|
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||||
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
"https://spacesops.com/getspaces?app=spaces-wallet&format=json",
|
||||||
|
{ cache: "no-store" }
|
||||||
|
);
|
||||||
|
const body = await response.text();
|
||||||
|
res.status(response.status).send(body);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(502).json({ success: false, error: "Unable to load spaces" });
|
||||||
|
}
|
||||||
|
};
|
||||||
+101
@@ -251,6 +251,36 @@
|
|||||||
border-radius: 999px;
|
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 */
|
||||||
footer {
|
footer {
|
||||||
padding: 2.5rem 0 3rem;
|
padding: 2.5rem 0 3rem;
|
||||||
@@ -374,6 +404,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</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>
|
<section>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<h2>Built for crypto natives</h2>
|
<h2>Built for crypto natives</h2>
|
||||||
@@ -423,5 +464,65 @@
|
|||||||
<p>© 2026 Lunde Cognitive Effects Inc.</p>
|
<p>© 2026 Lunde Cognitive Effects Inc.</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
{
|
{
|
||||||
"headers": [
|
"headers": [
|
||||||
|
{
|
||||||
|
"source": "/api/spaces",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Cache-Control",
|
||||||
|
"value": "no-store, no-cache, must-revalidate"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"source": "/apk/(.*\\.apk)",
|
"source": "/apk/(.*\\.apk)",
|
||||||
"headers": [
|
"headers": [
|
||||||
|
|||||||
Reference in New Issue
Block a user