refactor: standardize module component UI across all rApps
Consistent nav headers, button styles, and layout patterns across calendar, cart, choices, data, forum, funds, inbox, maps, network, notes, providers, trips, vote, and work modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e7ce57ce0b
commit
b299caf433
|
|
@ -79,13 +79,13 @@ class FolkCalendarView extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.header { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.nav-btn { padding: 6px 12px; border-radius: 6px; border: 1px solid #444; background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 16px; }
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 16px; }
|
||||||
.nav-btn:hover { border-color: #666; }
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
.header-title { font-size: 18px; font-weight: 600; flex: 1; text-align: center; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; text-align: center; color: #e2e8f0; }
|
||||||
.toggle-btn { padding: 6px 12px; border-radius: 6px; border: 1px solid #444; background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 12px; }
|
.toggle-btn { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 12px; }
|
||||||
.toggle-btn.active { border-color: #6366f1; color: #6366f1; }
|
.toggle-btn.active { border-color: #6366f1; color: #6366f1; }
|
||||||
.create-btn { padding: 6px 14px; border-radius: 6px; border: none; background: #6366f1; color: #fff; font-weight: 600; cursor: pointer; font-size: 12px; }
|
.rapp-nav__btn { padding: 6px 14px; border-radius: 6px; border: none; background: #4f46e5; color: #fff; font-weight: 600; cursor: pointer; font-size: 12px; }
|
||||||
|
|
||||||
.weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 4px; }
|
.weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 4px; }
|
||||||
.weekday { text-align: center; font-size: 11px; color: #666; padding: 4px; font-weight: 600; }
|
.weekday { text-align: center; font-size: 11px; color: #666; padding: 4px; font-weight: 600; }
|
||||||
|
|
@ -119,11 +119,11 @@ class FolkCalendarView extends HTMLElement {
|
||||||
|
|
||||||
${this.error ? `<div style="color:#ef5350;text-align:center;padding:8px">${this.esc(this.error)}</div>` : ""}
|
${this.error ? `<div style="color:#ef5350;text-align:center;padding:8px">${this.esc(this.error)}</div>` : ""}
|
||||||
|
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" id="prev">\u2190</button>
|
<button class="rapp-nav__back" id="prev">\u2190</button>
|
||||||
<span class="header-title">${monthName} ${year}</span>
|
<span class="rapp-nav__title">${monthName} ${year}</span>
|
||||||
<button class="toggle-btn ${this.showLunar ? "active" : ""}" id="toggle-lunar">\u{1F319} Lunar</button>
|
<button class="toggle-btn ${this.showLunar ? "active" : ""}" id="toggle-lunar">\u{1F319} Lunar</button>
|
||||||
<button class="nav-btn" id="next">\u2192</button>
|
<button class="rapp-nav__back" id="next">\u2192</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.sources.length > 0 ? `<div class="sources">
|
${this.sources.length > 0 ? `<div class="sources">
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ class FolkCartShop extends HTMLElement {
|
||||||
this.shadow.innerHTML = `
|
this.shadow.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
:host { display: block; padding: 1.5rem; }
|
:host { display: block; padding: 1.5rem; }
|
||||||
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
|
.rapp-nav { display: flex; gap: 8px; align-items: center; margin-bottom: 1rem; min-height: 36px; }
|
||||||
.header h2 { margin: 0; color: #f1f5f9; font-size: 1.5rem; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; }
|
||||||
.tabs { display: flex; gap: 0.5rem; }
|
.tabs { display: flex; gap: 0.5rem; }
|
||||||
.tab { padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; cursor: pointer; font-size: 0.875rem; }
|
.tab { padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; cursor: pointer; font-size: 0.875rem; }
|
||||||
.tab:hover { border-color: #475569; color: #f1f5f9; }
|
.tab:hover { border-color: #475569; color: #f1f5f9; }
|
||||||
|
|
@ -77,8 +77,8 @@ class FolkCartShop extends HTMLElement {
|
||||||
.loading { text-align: center; padding: 3rem; color: #94a3b8; }
|
.loading { text-align: center; padding: 3rem; color: #94a3b8; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<h2>\u{1F6D2} Community Shop</h2>
|
<span class="rapp-nav__title">Shop</span>
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<button class="tab ${this.view === 'catalog' ? 'active' : ''}" data-view="catalog">\u{1F4E6} Catalog (${this.catalog.length})</button>
|
<button class="tab ${this.view === 'catalog' ? 'active' : ''}" data-view="catalog">\u{1F4E6} Catalog (${this.catalog.length})</button>
|
||||||
<button class="tab ${this.view === 'orders' ? 'active' : ''}" data-view="orders">\u{1F4CB} Orders (${this.orders.length})</button>
|
<button class="tab ${this.view === 'orders' ? 'active' : ''}" data-view="orders">\u{1F4CB} Orders (${this.orders.length})</button>
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ class FolkChoicesDashboard extends HTMLElement {
|
||||||
this.shadow.innerHTML = `
|
this.shadow.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
:host { display: block; padding: 1.5rem; }
|
:host { display: block; padding: 1.5rem; }
|
||||||
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
|
.rapp-nav { display: flex; gap: 8px; align-items: center; margin-bottom: 1rem; min-height: 36px; }
|
||||||
.header h2 { margin: 0; color: #f1f5f9; font-size: 1.5rem; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; }
|
||||||
.create-btns { display: flex; gap: 0.5rem; }
|
.create-btns { display: flex; gap: 0.5rem; }
|
||||||
.create-btn { padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; cursor: pointer; font-size: 0.875rem; text-decoration: none; }
|
.create-btn { padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; cursor: pointer; font-size: 0.875rem; text-decoration: none; }
|
||||||
.create-btn:hover { border-color: #6366f1; color: #f1f5f9; }
|
.create-btn:hover { border-color: #6366f1; color: #f1f5f9; }
|
||||||
|
|
@ -75,8 +75,8 @@ class FolkChoicesDashboard extends HTMLElement {
|
||||||
.info { background: rgba(99,102,241,0.1); border: 1px solid rgba(99,102,241,0.2); border-radius: 8px; padding: 1rem; margin-bottom: 1.5rem; color: #a5b4fc; font-size: 0.8125rem; }
|
.info { background: rgba(99,102,241,0.1); border: 1px solid rgba(99,102,241,0.2); border-radius: 8px; padding: 1rem; margin-bottom: 1.5rem; color: #a5b4fc; font-size: 0.8125rem; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<h2>\u2611 Choices</h2>
|
<span class="rapp-nav__title">Choices</span>
|
||||||
<div class="create-btns">
|
<div class="create-btns">
|
||||||
<a class="create-btn" href="/${this.space}/canvas" title="Open canvas to create choices">\u2795 New on Canvas</a>
|
<a class="create-btn" href="/${this.space}/canvas" title="Open canvas to create choices">\u2795 New on Canvas</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ class FolkAnalyticsView extends HTMLElement {
|
||||||
<style>
|
<style>
|
||||||
:host { display: block; min-height: 60vh; font-family: system-ui, sans-serif; color: #e2e8f0; }
|
:host { display: block; min-height: 60vh; font-family: system-ui, sans-serif; color: #e2e8f0; }
|
||||||
.container { max-width: 800px; margin: 0 auto; }
|
.container { max-width: 800px; margin: 0 auto; }
|
||||||
.hero { text-align: center; margin-bottom: 2rem; }
|
.desc { color: #94a3b8; font-size: 14px; line-height: 1.6; max-width: 600px; margin-bottom: 1.5rem; }
|
||||||
.hero h2 { font-size: 1.75rem; font-weight: 700; margin-bottom: 0.5rem; }
|
|
||||||
.hero p { color: #94a3b8; max-width: 480px; margin: 0 auto; }
|
|
||||||
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
|
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
|
||||||
.stat { text-align: center; background: rgba(15,23,42,0.5); border: 1px solid #1e293b; border-radius: 12px; padding: 1.25rem; }
|
.stat { text-align: center; background: rgba(15,23,42,0.5); border: 1px solid #1e293b; border-radius: 12px; padding: 1.25rem; }
|
||||||
.stat-value { font-size: 1.75rem; font-weight: 700; color: #22d3ee; }
|
.stat-value { font-size: 1.75rem; font-weight: 700; color: #22d3ee; }
|
||||||
|
|
@ -53,11 +51,11 @@ class FolkAnalyticsView extends HTMLElement {
|
||||||
.pillar h3 { font-size: 1rem; font-weight: 600; margin-bottom: 0.5rem; }
|
.pillar h3 { font-size: 1rem; font-weight: 600; margin-bottom: 0.5rem; }
|
||||||
.pillar p { font-size: 0.85rem; color: #94a3b8; line-height: 1.5; }
|
.pillar p { font-size: 0.85rem; color: #94a3b8; line-height: 1.5; }
|
||||||
.apps-section { margin-bottom: 2rem; }
|
.apps-section { margin-bottom: 2rem; }
|
||||||
.apps-title { text-align: center; font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem; }
|
.apps-title { font-size: 1rem; font-weight: 600; margin-bottom: 1rem; }
|
||||||
.apps-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; }
|
.apps-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||||
.app-chip { padding: 0.35rem 0.75rem; background: rgba(15,23,42,0.5); border: 1px solid #1e293b; border-radius: 20px; font-size: 0.8rem; color: #94a3b8; }
|
.app-chip { padding: 0.35rem 0.75rem; background: rgba(15,23,42,0.5); border: 1px solid #1e293b; border-radius: 20px; font-size: 0.8rem; color: #94a3b8; }
|
||||||
.cta { text-align: center; padding: 2rem; border-top: 1px solid #1e293b; }
|
.cta { padding: 1.5rem 0; border-top: 1px solid #1e293b; }
|
||||||
.cta a { display: inline-block; padding: 0.75rem 2rem; background: #22d3ee; color: #0f172a; border-radius: 8px; font-weight: 600; text-decoration: none; }
|
.cta a { display: inline-block; padding: 0.6rem 1.5rem; background: #22d3ee; color: #0f172a; border-radius: 8px; font-weight: 600; text-decoration: none; font-size: 0.85rem; }
|
||||||
.cta a:hover { opacity: 0.85; }
|
.cta a:hover { opacity: 0.85; }
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
|
@ -65,10 +63,7 @@ class FolkAnalyticsView extends HTMLElement {
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="hero">
|
<p class="desc">Zero-knowledge, cookieless, self-hosted analytics for the r* ecosystem. Know how your tools are used without compromising anyone's privacy.</p>
|
||||||
<h2>Privacy-First Analytics</h2>
|
|
||||||
<p>Zero-knowledge, cookieless, self-hosted analytics for the r* ecosystem. Know how your tools are used without compromising anyone's privacy.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat">
|
<div class="stat">
|
||||||
|
|
@ -108,14 +103,14 @@ class FolkAnalyticsView extends HTMLElement {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="apps-section">
|
<div class="apps-section">
|
||||||
<div class="apps-title">Tracking the r* Ecosystem</div>
|
<div class="apps-title">Tracked Apps</div>
|
||||||
<div class="apps-grid">
|
<div class="apps-grid">
|
||||||
${(stats.apps || []).map((a: string) => `<span class="app-chip">${a}</span>`).join("")}
|
${(stats.apps || []).map((a: string) => `<span class="app-chip">${a}</span>`).join("")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cta">
|
<div class="cta">
|
||||||
<a href="${stats.dashboardUrl}" target="_blank" rel="noopener">Open Dashboard</a>
|
<a href="${stats.dashboardUrl}" target="_blank" rel="noopener">Open Full Dashboard →</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -164,15 +164,19 @@ class FolkForumDashboard extends HTMLElement {
|
||||||
|
|
||||||
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
|
||||||
|
|
||||||
.toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; }
|
||||||
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.rapp-nav__btn { padding: 6px 14px; border-radius: 6px; border: none; background: #4f46e5; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
||||||
|
.rapp-nav__btn:hover { background: #6366f1; }
|
||||||
button {
|
button {
|
||||||
padding: 6px 14px; border-radius: 4px; border: 1px solid #555;
|
padding: 6px 14px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1);
|
||||||
background: #2a4a7a; color: #e0e0e0; cursor: pointer; font-size: 13px;
|
background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px;
|
||||||
}
|
}
|
||||||
button:hover { background: #3a5a9a; }
|
button:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
button.danger { background: #7a2a2a; }
|
button.danger { background: rgba(239,68,68,0.15); border-color: rgba(239,68,68,0.3); color: #ef4444; }
|
||||||
button.danger:hover { background: #9a3a3a; }
|
button.danger:hover { background: rgba(239,68,68,0.25); }
|
||||||
button.secondary { background: #333; }
|
|
||||||
|
|
||||||
input, select {
|
input, select {
|
||||||
background: #2a2a3e; border: 1px solid #444; color: #e0e0e0;
|
background: #2a2a3e; border: 1px solid #444; color: #e0e0e0;
|
||||||
|
|
@ -229,9 +233,9 @@ class FolkForumDashboard extends HTMLElement {
|
||||||
|
|
||||||
private renderList(): string {
|
private renderList(): string {
|
||||||
return `
|
return `
|
||||||
<div class="toolbar">
|
<div class="rapp-nav">
|
||||||
<h2 style="margin:0;font-size:18px">\uD83D\uDCAC Forum Instances</h2>
|
<span class="rapp-nav__title">Forum Instances</span>
|
||||||
<button data-action="show-create">+ New Forum</button>
|
<button class="rapp-nav__btn" data-action="show-create">+ New Forum</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.loading ? '<div class="loading">Loading...</div>' : ""}
|
${this.loading ? '<div class="loading">Loading...</div>' : ""}
|
||||||
|
|
@ -259,8 +263,9 @@ class FolkForumDashboard extends HTMLElement {
|
||||||
if (!inst) return "";
|
if (!inst) return "";
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="toolbar">
|
<div class="rapp-nav">
|
||||||
<button class="secondary" data-action="back">\u2190 Back</button>
|
<button class="rapp-nav__back" data-action="back">\u2190 Forums</button>
|
||||||
|
<span class="rapp-nav__title">${this.esc(inst.name)}</span>
|
||||||
${inst.status !== "destroyed" ? `<button class="danger" data-action="destroy" data-id="${inst.id}">Destroy</button>` : ""}
|
${inst.status !== "destroyed" ? `<button class="danger" data-action="destroy" data-id="${inst.id}">Destroy</button>` : ""}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -303,8 +308,9 @@ class FolkForumDashboard extends HTMLElement {
|
||||||
|
|
||||||
private renderCreate(): string {
|
private renderCreate(): string {
|
||||||
return `
|
return `
|
||||||
<div class="toolbar">
|
<div class="rapp-nav">
|
||||||
<button class="secondary" data-action="back">\u2190 Back</button>
|
<button class="rapp-nav__back" data-action="back">\u2190 Forums</button>
|
||||||
|
<span class="rapp-nav__title">Deploy New Forum</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detail-panel">
|
<div class="detail-panel">
|
||||||
|
|
|
||||||
|
|
@ -193,23 +193,23 @@ class FolkFundsApp extends HTMLElement {
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="funds-landing">
|
<div class="funds-landing">
|
||||||
<div class="funds-hero">
|
<div class="rapp-nav">
|
||||||
<h1 class="funds-hero__title">rFunds</h1>
|
<span class="rapp-nav__title">Flows</span>
|
||||||
<p class="funds-hero__subtitle">Token Bonding Flow Funnel</p>
|
<div class="rapp-nav__actions">
|
||||||
<p class="funds-hero__desc">
|
<a href="${this.esc(demoUrl)}" class="rapp-nav__btn rapp-nav__btn--secondary">Demo</a>
|
||||||
Design transparent resource flows with sufficiency-based cascading.
|
|
||||||
Funnels fill to their threshold, then overflow routes surplus to the next layer —
|
|
||||||
ensuring every level has <em>enough</em> before abundance cascades forward.
|
|
||||||
</p>
|
|
||||||
<div class="funds-hero__actions">
|
|
||||||
<a href="${this.esc(demoUrl)}" class="funds-hero__cta">Try the Demo →</a>
|
|
||||||
${authed
|
${authed
|
||||||
? `<button class="funds-hero__cta funds-hero__cta--secondary" data-action="create-flow">Create Flow</button>`
|
? `<button class="rapp-nav__btn" data-action="create-flow">+ Create Flow</button>`
|
||||||
: `<span class="funds-hero__auth-hint">Sign in to create flows</span>`
|
: `<span style="font-size:12px;color:#64748b">Sign in to create flows</span>`
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="funds-desc" style="color:#94a3b8;font-size:14px;line-height:1.6;max-width:600px;margin-bottom:24px">
|
||||||
|
Design transparent resource flows with sufficiency-based cascading.
|
||||||
|
Funnels fill to their threshold, then overflow routes surplus to the next layer —
|
||||||
|
ensuring every level has <em style="color:#fbbf24;font-style:normal;font-weight:600">enough</em> before abundance cascades forward.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="funds-features">
|
<div class="funds-features">
|
||||||
<div class="funds-features__grid">
|
<div class="funds-features__grid">
|
||||||
<div class="funds-features__card">
|
<div class="funds-features__card">
|
||||||
|
|
@ -316,10 +316,10 @@ class FolkFundsApp extends HTMLElement {
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="funds-detail">
|
<div class="funds-detail">
|
||||||
<div class="funds-detail__header">
|
<div class="rapp-nav">
|
||||||
<a href="${this.esc(backUrl)}" class="funds-detail__back">← All Flows</a>
|
<a href="${this.esc(backUrl)}" class="rapp-nav__back">← Flows</a>
|
||||||
<h1 class="funds-detail__title">${this.esc(this.flowName || "Flow Detail")}</h1>
|
<span class="rapp-nav__title">${this.esc(this.flowName || "Flow Detail")}</span>
|
||||||
${this.isDemo ? '<span class="funds-detail__badge">Demo</span>' : ""}
|
${this.isDemo ? '<span class="rapp-nav__badge">Demo</span>' : ""}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="funds-tabs">
|
<div class="funds-tabs">
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
/* ── Funds module theme ───────────────────────────────── */
|
/* ── Funds module theme ───────────────────────────────── */
|
||||||
body[data-theme="light"] main {
|
|
||||||
background: #0f172a;
|
|
||||||
min-height: calc(100vh - 56px);
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Shared utility classes ──────────────────────────── */
|
/* ── Shared utility classes ──────────────────────────── */
|
||||||
.funds-loading { text-align: center; color: #64748b; padding: 48px 16px; font-size: 14px; }
|
.funds-loading { text-align: center; color: #64748b; padding: 48px 16px; font-size: 14px; }
|
||||||
|
|
@ -12,34 +7,6 @@ body[data-theme="light"] main {
|
||||||
/* ── Landing page ────────────────────────────────────── */
|
/* ── Landing page ────────────────────────────────────── */
|
||||||
.funds-landing { max-width: 960px; margin: 0 auto; padding: 24px 20px 64px; }
|
.funds-landing { max-width: 960px; margin: 0 auto; padding: 24px 20px 64px; }
|
||||||
|
|
||||||
.funds-hero {
|
|
||||||
text-align: center;
|
|
||||||
padding: 56px 20px 48px;
|
|
||||||
border-bottom: 1px solid #1e293b;
|
|
||||||
margin-bottom: 48px;
|
|
||||||
}
|
|
||||||
.funds-hero__title {
|
|
||||||
font-size: 42px; font-weight: 800; margin: 0 0 8px;
|
|
||||||
background: linear-gradient(135deg, #0ea5e9, #6366f1, #ec4899);
|
|
||||||
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
.funds-hero__subtitle { font-size: 18px; color: #94a3b8; margin: 0 0 16px; font-weight: 500; }
|
|
||||||
.funds-hero__desc { font-size: 15px; color: #64748b; line-height: 1.7; max-width: 560px; margin: 0 auto 28px; }
|
|
||||||
.funds-hero__desc em { color: #fbbf24; font-style: normal; font-weight: 600; }
|
|
||||||
.funds-hero__actions { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; }
|
|
||||||
.funds-hero__cta {
|
|
||||||
display: inline-block; padding: 10px 24px; border-radius: 8px;
|
|
||||||
background: #4f46e5; color: #fff; text-decoration: none; font-weight: 600; font-size: 14px;
|
|
||||||
border: none; cursor: pointer; transition: background 0.2s;
|
|
||||||
}
|
|
||||||
.funds-hero__cta:hover { background: #6366f1; }
|
|
||||||
.funds-hero__cta--secondary {
|
|
||||||
background: transparent; border: 1px solid #4f46e5; color: #a5b4fc;
|
|
||||||
}
|
|
||||||
.funds-hero__cta--secondary:hover { background: rgba(79,70,229,0.15); }
|
|
||||||
.funds-hero__auth-hint { font-size: 13px; color: #64748b; }
|
|
||||||
|
|
||||||
/* Features grid */
|
/* Features grid */
|
||||||
.funds-features { margin-bottom: 48px; }
|
.funds-features { margin-bottom: 48px; }
|
||||||
.funds-features__grid {
|
.funds-features__grid {
|
||||||
|
|
@ -106,16 +73,6 @@ body[data-theme="light"] main {
|
||||||
|
|
||||||
/* ── Detail view ─────────────────────────────────────── */
|
/* ── Detail view ─────────────────────────────────────── */
|
||||||
.funds-detail { max-width: 1100px; margin: 0 auto; padding: 16px 20px 64px; }
|
.funds-detail { max-width: 1100px; margin: 0 auto; padding: 16px 20px 64px; }
|
||||||
.funds-detail__header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
|
|
||||||
.funds-detail__back {
|
|
||||||
color: #64748b; text-decoration: none; font-size: 13px; padding: 4px 0;
|
|
||||||
}
|
|
||||||
.funds-detail__back:hover { color: #e2e8f0; }
|
|
||||||
.funds-detail__title { font-size: 22px; font-weight: 700; color: #e2e8f0; margin: 0; flex: 1; }
|
|
||||||
.funds-detail__badge {
|
|
||||||
font-size: 11px; font-weight: 600; color: #fbbf24; background: rgba(251,191,36,0.15);
|
|
||||||
border: 1px solid rgba(251,191,36,0.3); border-radius: 4px; padding: 2px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Tabs ────────────────────────────────────────────── */
|
/* ── Tabs ────────────────────────────────────────────── */
|
||||||
.funds-tabs {
|
.funds-tabs {
|
||||||
|
|
|
||||||
|
|
@ -90,11 +90,11 @@ class FolkInboxClient extends HTMLElement {
|
||||||
<style>
|
<style>
|
||||||
:host { display: block; min-height: 60vh; font-family: system-ui, sans-serif; color: #e2e8f0; }
|
:host { display: block; min-height: 60vh; font-family: system-ui, sans-serif; color: #e2e8f0; }
|
||||||
.container { max-width: 1000px; margin: 0 auto; }
|
.container { max-width: 1000px; margin: 0 auto; }
|
||||||
.nav { display: flex; gap: 0.5rem; margin-bottom: 1.5rem; align-items: center; }
|
.rapp-nav { display: flex; gap: 0.5rem; margin-bottom: 1rem; align-items: center; min-height: 36px; }
|
||||||
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 0.8rem; }
|
||||||
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
.nav-btn { padding: 0.4rem 1rem; border-radius: 8px; border: 1px solid #334155; background: transparent; color: #94a3b8; cursor: pointer; font-size: 0.8rem; }
|
.nav-btn { padding: 0.4rem 1rem; border-radius: 8px; border: 1px solid #334155; background: transparent; color: #94a3b8; cursor: pointer; font-size: 0.8rem; }
|
||||||
.nav-btn.active { background: #6366f1; color: white; border-color: #6366f1; }
|
.nav-btn.active { background: #6366f1; color: white; border-color: #6366f1; }
|
||||||
.back-btn { padding: 0.4rem 0.75rem; border-radius: 8px; border: 1px solid #334155; background: transparent; color: #94a3b8; cursor: pointer; font-size: 0.8rem; margin-right: 0.5rem; }
|
|
||||||
.back-btn:hover { background: rgba(51,65,85,0.5); }
|
|
||||||
.card { background: rgba(15,23,42,0.5); border: 1px solid #1e293b; border-radius: 12px; padding: 1.25rem; margin-bottom: 0.75rem; cursor: pointer; transition: border-color 0.2s; }
|
.card { background: rgba(15,23,42,0.5); border: 1px solid #1e293b; border-radius: 12px; padding: 1.25rem; margin-bottom: 0.75rem; cursor: pointer; transition: border-color 0.2s; }
|
||||||
.card:hover { border-color: #6366f1; }
|
.card:hover { border-color: #6366f1; }
|
||||||
.card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; }
|
.card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; }
|
||||||
|
|
@ -154,8 +154,8 @@ class FolkInboxClient extends HTMLElement {
|
||||||
items.unshift({ id: "threads", label: this.currentMailbox.name });
|
items.unshift({ id: "threads", label: this.currentMailbox.name });
|
||||||
}
|
}
|
||||||
return `
|
return `
|
||||||
<div class="nav">
|
<div class="rapp-nav">
|
||||||
${this.view !== "mailboxes" ? `<button class="back-btn" data-action="back">←</button>` : ""}
|
${this.view !== "mailboxes" ? `<button class="rapp-nav__back" data-action="back">←</button>` : ""}
|
||||||
${items.map((i) => `<button class="nav-btn ${this.view === i.id ? "active" : ""}" data-nav="${i.id}">${i.label}</button>`).join("")}
|
${items.map((i) => `<button class="nav-btn ${this.view === i.id ? "active" : ""}" data-nav="${i.id}">${i.label}</button>`).join("")}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -83,13 +83,10 @@ class FolkMapViewer extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.header { display: flex; gap: 8px; margin-bottom: 20px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.nav-btn {
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; }
|
||||||
padding: 6px 14px; border-radius: 6px; border: 1px solid #444;
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 13px;
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
}
|
|
||||||
.nav-btn:hover { border-color: #666; }
|
|
||||||
.header-title { font-size: 18px; font-weight: 600; margin-left: 8px; flex: 1; }
|
|
||||||
|
|
||||||
.status-dot {
|
.status-dot {
|
||||||
width: 8px; height: 8px; border-radius: 50%; display: inline-block;
|
width: 8px; height: 8px; border-radius: 50%; display: inline-block;
|
||||||
|
|
@ -97,11 +94,8 @@ class FolkMapViewer extends HTMLElement {
|
||||||
.status-connected { background: #22c55e; }
|
.status-connected { background: #22c55e; }
|
||||||
.status-disconnected { background: #ef4444; }
|
.status-disconnected { background: #ef4444; }
|
||||||
|
|
||||||
.create-btn {
|
.rapp-nav__btn { padding: 6px 14px; border-radius: 6px; border: none; background: #4f46e5; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
||||||
padding: 10px 20px; border-radius: 8px; border: none;
|
.rapp-nav__btn:hover { background: #6366f1; }
|
||||||
background: #6366f1; color: #fff; font-weight: 600; cursor: pointer; font-size: 14px;
|
|
||||||
}
|
|
||||||
.create-btn:hover { background: #4f46e5; }
|
|
||||||
|
|
||||||
.room-card {
|
.room-card {
|
||||||
background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
|
background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
|
||||||
|
|
@ -162,11 +156,11 @@ class FolkMapViewer extends HTMLElement {
|
||||||
|
|
||||||
private renderLobby(): string {
|
private renderLobby(): string {
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<span class="header-title">Map Rooms</span>
|
<span class="rapp-nav__title">Map Rooms</span>
|
||||||
<span class="status-dot ${this.syncStatus === "connected" ? "status-connected" : "status-disconnected"}"></span>
|
<span class="status-dot ${this.syncStatus === "connected" ? "status-connected" : "status-disconnected"}"></span>
|
||||||
<span style="font-size:12px;color:#888;margin-right:12px">${this.syncStatus === "connected" ? "Sync online" : "Sync offline"}</span>
|
<span style="font-size:12px;color:#888;margin-right:12px">${this.syncStatus === "connected" ? "Sync online" : "Sync offline"}</span>
|
||||||
<button class="create-btn" id="create-room">+ New Room</button>
|
<button class="rapp-nav__btn" id="create-room">+ New Room</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this.rooms.length > 0 ? this.rooms.map((r) => `
|
${this.rooms.length > 0 ? this.rooms.map((r) => `
|
||||||
|
|
@ -186,9 +180,9 @@ class FolkMapViewer extends HTMLElement {
|
||||||
private renderMap(): string {
|
private renderMap(): string {
|
||||||
const shareUrl = `${window.location.origin}/${this.space}/maps/${this.room}`;
|
const shareUrl = `${window.location.origin}/${this.space}/maps/${this.room}`;
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="lobby">Back</button>
|
<button class="rapp-nav__back" data-back="lobby">\u2190 Rooms</button>
|
||||||
<span class="header-title">\u{1F5FA} ${this.esc(this.room)}</span>
|
<span class="rapp-nav__title">\u{1F5FA} ${this.esc(this.room)}</span>
|
||||||
<span class="status-dot ${this.syncStatus === "connected" ? "status-connected" : "status-disconnected"}"></span>
|
<span class="status-dot ${this.syncStatus === "connected" ? "status-connected" : "status-disconnected"}"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ class FolkGraphViewer extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.header { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.header-title { font-size: 18px; font-weight: 600; flex: 1; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; }
|
||||||
|
|
||||||
.toolbar { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; flex-wrap: wrap; }
|
.toolbar { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; flex-wrap: wrap; }
|
||||||
.search-input {
|
.search-input {
|
||||||
|
|
@ -99,8 +99,8 @@ class FolkGraphViewer extends HTMLElement {
|
||||||
|
|
||||||
${this.error ? `<div style="color:#ef5350;text-align:center;padding:8px">${this.esc(this.error)}</div>` : ""}
|
${this.error ? `<div style="color:#ef5350;text-align:center;padding:8px">${this.esc(this.error)}</div>` : ""}
|
||||||
|
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<span class="header-title">\u{1F310} Network Graph</span>
|
<span class="rapp-nav__title">Network Graph</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
|
|
|
||||||
|
|
@ -457,18 +457,12 @@ class FolkNotesApp extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.header { display: flex; gap: 8px; margin-bottom: 20px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.nav-btn {
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; }
|
||||||
padding: 6px 14px; border-radius: 6px; border: 1px solid #444;
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 13px;
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
}
|
.rapp-nav__btn { padding: 6px 14px; border-radius: 6px; border: none; background: #4f46e5; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
||||||
.nav-btn:hover { border-color: #666; }
|
.rapp-nav__btn:hover { background: #6366f1; }
|
||||||
.header-title { font-size: 18px; font-weight: 600; margin-left: 8px; flex: 1; }
|
|
||||||
.create-btn {
|
|
||||||
padding: 8px 16px; border-radius: 8px; border: none;
|
|
||||||
background: #6366f1; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px;
|
|
||||||
}
|
|
||||||
.create-btn:hover { background: #4f46e5; }
|
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
width: 100%; padding: 10px 14px; border-radius: 8px;
|
width: 100%; padding: 10px 14px; border-radius: 8px;
|
||||||
|
|
@ -543,9 +537,9 @@ class FolkNotesApp extends HTMLElement {
|
||||||
|
|
||||||
private renderNotebooks(): string {
|
private renderNotebooks(): string {
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<span class="header-title">Notebooks</span>
|
<span class="rapp-nav__title">Notebooks</span>
|
||||||
<button class="create-btn" id="create-notebook">+ New Notebook</button>
|
<button class="rapp-nav__btn" id="create-notebook">+ New Notebook</button>
|
||||||
</div>
|
</div>
|
||||||
<input class="search-bar" type="text" placeholder="Search notes..." id="search-input" value="${this.esc(this.searchQuery)}">
|
<input class="search-bar" type="text" placeholder="Search notes..." id="search-input" value="${this.esc(this.searchQuery)}">
|
||||||
|
|
||||||
|
|
@ -578,10 +572,10 @@ class FolkNotesApp extends HTMLElement {
|
||||||
? `<span class="sync-badge ${this.syncConnected ? "connected" : "disconnected"}" title="${this.syncConnected ? "Live sync" : "Reconnecting..."}"></span>`
|
? `<span class="sync-badge ${this.syncConnected ? "connected" : "disconnected"}" title="${this.syncConnected ? "Live sync" : "Reconnecting..."}"></span>`
|
||||||
: "";
|
: "";
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="notebooks">Back</button>
|
<button class="rapp-nav__back" data-back="notebooks">\u2190 Notebooks</button>
|
||||||
<span class="header-title" style="color:${nb.cover_color}">${this.esc(nb.title)}${syncBadge}</span>
|
<span class="rapp-nav__title" style="color:${nb.cover_color}">${this.esc(nb.title)}${syncBadge}</span>
|
||||||
<button class="create-btn" id="create-note">+ New Note</button>
|
<button class="rapp-nav__btn" id="create-note">+ New Note</button>
|
||||||
</div>
|
</div>
|
||||||
${nb.notes && nb.notes.length > 0
|
${nb.notes && nb.notes.length > 0
|
||||||
? nb.notes.map((n) => this.renderNoteItem(n)).join("")
|
? nb.notes.map((n) => this.renderNoteItem(n)).join("")
|
||||||
|
|
@ -611,11 +605,11 @@ class FolkNotesApp extends HTMLElement {
|
||||||
const n = this.selectedNote!;
|
const n = this.selectedNote!;
|
||||||
const isAutomerge = !!(this.doc?.items?.[n.id]);
|
const isAutomerge = !!(this.doc?.items?.[n.id]);
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="${this.selectedNotebook ? "notebook" : "notebooks"}">Back</button>
|
<button class="rapp-nav__back" data-back="${this.selectedNotebook ? "notebook" : "notebooks"}">\u2190 ${this.selectedNotebook ? this.esc(this.selectedNotebook.title) : "Notebooks"}</button>
|
||||||
${isAutomerge
|
${isAutomerge
|
||||||
? `<input class="editable-title" id="note-title-input" value="${this.esc(n.title)}" placeholder="Note title...">`
|
? `<input class="editable-title" id="note-title-input" value="${this.esc(n.title)}" placeholder="Note title...">`
|
||||||
: `<span class="header-title">${this.getNoteIcon(n.type)} ${this.esc(n.title)}</span>`
|
: `<span class="rapp-nav__title">${this.getNoteIcon(n.type)} ${this.esc(n.title)}</span>`
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="note-content" ${isAutomerge ? 'contenteditable="true" id="note-content-editable"' : ""}>${n.content || '<em style="color:#666">Empty note</em>'}</div>
|
<div class="note-content" ${isAutomerge ? 'contenteditable="true" id="note-content-editable"' : ""}>${n.content || '<em style="color:#666">Empty note</em>'}</div>
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ class FolkProviderDirectory extends HTMLElement {
|
||||||
this.shadow.innerHTML = `
|
this.shadow.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
:host { display: block; padding: 1.5rem; }
|
:host { display: block; padding: 1.5rem; }
|
||||||
.header { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; margin-bottom: 1.5rem; }
|
.rapp-nav { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin-bottom: 1rem; min-height: 36px; }
|
||||||
.header h2 { margin: 0; font-size: 1.5rem; color: #f1f5f9; flex: 1; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; color: #e2e8f0; flex: 1; }
|
||||||
.search { padding: 0.5rem 0.75rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.875rem; width: 240px; }
|
.search { padding: 0.5rem 0.75rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.875rem; width: 240px; }
|
||||||
.search:focus { outline: none; border-color: #6366f1; }
|
.search:focus { outline: none; border-color: #6366f1; }
|
||||||
.locate-btn { padding: 0.5rem 0.75rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; cursor: pointer; font-size: 0.75rem; }
|
.locate-btn { padding: 0.5rem 0.75rem; border-radius: 8px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; cursor: pointer; font-size: 0.75rem; }
|
||||||
|
|
@ -99,8 +99,8 @@ class FolkProviderDirectory extends HTMLElement {
|
||||||
.empty { text-align: center; padding: 3rem; color: #64748b; }
|
.empty { text-align: center; padding: 3rem; color: #64748b; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<h2>\u{1F3ED} Provider Directory</h2>
|
<span class="rapp-nav__title">Provider Directory</span>
|
||||||
<input class="search" type="text" placeholder="Search providers..." value="${this.searchQuery}">
|
<input class="search" type="text" placeholder="Search providers..." value="${this.searchQuery}">
|
||||||
<button class="locate-btn ${this.userLat ? 'active' : ''}">\u{1F4CD} ${this.userLat ? 'Nearby' : 'Use location'}</button>
|
<button class="locate-btn ${this.userLat ? 'active' : ''}">\u{1F4CD} ${this.userLat ? 'Nearby' : 'Use location'}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -409,9 +409,9 @@ class FolkRoutePlanner extends HTMLElement {
|
||||||
<style>
|
<style>
|
||||||
:host { display: block; font-family: -apple-system, system-ui, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: -apple-system, system-ui, sans-serif; color: #e0e0e0; }
|
||||||
.container { background: #1a1a2e; border-radius: 12px; overflow: hidden; }
|
.container { background: #1a1a2e; border-radius: 12px; overflow: hidden; }
|
||||||
.header { padding: 16px 20px; border-bottom: 1px solid rgba(255,255,255,0.08); }
|
.rapp-nav { padding: 16px 20px; border-bottom: 1px solid rgba(255,255,255,0.08); }
|
||||||
.header h2 { margin: 0 0 4px 0; font-size: 18px; color: #fff; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; color: #e2e8f0; display: block; margin-bottom: 4px; }
|
||||||
.header p { margin: 0; font-size: 13px; opacity: 0.6; }
|
.rapp-nav__desc { font-size: 13px; color: #94a3b8; }
|
||||||
|
|
||||||
.input-panel { padding: 16px 20px; display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; border-bottom: 1px solid rgba(255,255,255,0.08); }
|
.input-panel { padding: 16px 20px; display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; border-bottom: 1px solid rgba(255,255,255,0.08); }
|
||||||
.route-group { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
.route-group { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||||||
|
|
@ -459,9 +459,9 @@ class FolkRoutePlanner extends HTMLElement {
|
||||||
.math-note { padding: 12px 20px; border-top: 1px solid rgba(255,255,255,0.05); font-size: 11px; opacity: 0.4; font-family: monospace; }
|
.math-note { padding: 12px 20px; border-top: 1px solid rgba(255,255,255,0.05); font-size: 11px; opacity: 0.4; font-family: monospace; }
|
||||||
</style>
|
</style>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<h2>rTrips — Route Planner</h2>
|
<span class="rapp-nav__title">Route Planner</span>
|
||||||
<p>Plan paths between destinations. Fit conic arcs and find where routes intersect.</p>
|
<span class="rapp-nav__desc">Plan paths between destinations. Fit conic arcs and find where routes intersect.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-panel">
|
<div class="input-panel">
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,12 @@ class FolkTripsPlanner extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.header { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.nav-btn { padding: 6px 14px; border-radius: 6px; border: 1px solid #444; background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 13px; }
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; }
|
||||||
.header-title { font-size: 18px; font-weight: 600; margin-left: 8px; flex: 1; }
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
.create-btn { padding: 8px 16px; border-radius: 8px; border: none; background: #14b8a6; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.create-btn:hover { background: #0d9488; }
|
.rapp-nav__btn { padding: 6px 14px; border-radius: 6px; border: none; background: #14b8a6; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
||||||
|
.rapp-nav__btn:hover { background: #0d9488; }
|
||||||
|
|
||||||
.trip-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
|
.trip-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
|
||||||
.trip-card { background: #1e1e2e; border: 1px solid #333; border-radius: 10px; padding: 16px; cursor: pointer; transition: border-color 0.2s; }
|
.trip-card { background: #1e1e2e; border: 1px solid #333; border-radius: 10px; padding: 16px; cursor: pointer; transition: border-color 0.2s; }
|
||||||
|
|
@ -114,9 +115,9 @@ class FolkTripsPlanner extends HTMLElement {
|
||||||
|
|
||||||
private renderList(): string {
|
private renderList(): string {
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<span class="header-title">\u2708\uFE0F My Trips</span>
|
<span class="rapp-nav__title">My Trips</span>
|
||||||
<button class="create-btn" id="create-trip">+ Plan a Trip</button>
|
<button class="rapp-nav__btn" id="create-trip">+ Plan a Trip</button>
|
||||||
</div>
|
</div>
|
||||||
${this.trips.length > 0 ? `<div class="trip-grid">
|
${this.trips.length > 0 ? `<div class="trip-grid">
|
||||||
${this.trips.map(t => `
|
${this.trips.map(t => `
|
||||||
|
|
@ -141,9 +142,9 @@ class FolkTripsPlanner extends HTMLElement {
|
||||||
if (!this.trip) return '<div class="empty">Loading...</div>';
|
if (!this.trip) return '<div class="empty">Loading...</div>';
|
||||||
const t = this.trip;
|
const t = this.trip;
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="list">\u2190 Back</button>
|
<button class="rapp-nav__back" data-back="list">\u2190 Trips</button>
|
||||||
<span class="header-title">\u2708\uFE0F ${this.esc(t.title)}</span>
|
<span class="rapp-nav__title">${this.esc(t.title)}</span>
|
||||||
<span class="trip-status status-${t.status || "PLANNING"}">${t.status || "PLANNING"}</span>
|
<span class="trip-status status-${t.status || "PLANNING"}">${t.status || "PLANNING"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
|
|
|
||||||
|
|
@ -145,14 +145,10 @@ class FolkVoteDashboard extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.nav { display: flex; gap: 8px; margin-bottom: 20px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.nav-btn {
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; }
|
||||||
padding: 6px 14px; border-radius: 6px; border: 1px solid #444;
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 13px;
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
}
|
|
||||||
.nav-btn:hover { border-color: #666; }
|
|
||||||
.nav-btn.active { border-color: #6366f1; color: #a5b4fc; }
|
|
||||||
.nav-title { font-size: 18px; font-weight: 600; margin-left: 8px; }
|
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
|
background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
|
||||||
|
|
@ -213,8 +209,8 @@ class FolkVoteDashboard extends HTMLElement {
|
||||||
|
|
||||||
private renderSpaces(): string {
|
private renderSpaces(): string {
|
||||||
return `
|
return `
|
||||||
<div class="nav">
|
<div class="rapp-nav">
|
||||||
<span class="nav-title">Voting Spaces</span>
|
<span class="rapp-nav__title">Voting Spaces</span>
|
||||||
</div>
|
</div>
|
||||||
${this.spaces.length === 0 ? '<div class="empty">No voting spaces yet. Create one to get started.</div>' : ""}
|
${this.spaces.length === 0 ? '<div class="empty">No voting spaces yet. Create one to get started.</div>' : ""}
|
||||||
${this.spaces.map((s) => `
|
${this.spaces.map((s) => `
|
||||||
|
|
@ -234,9 +230,9 @@ class FolkVoteDashboard extends HTMLElement {
|
||||||
private renderProposals(): string {
|
private renderProposals(): string {
|
||||||
const s = this.selectedSpace!;
|
const s = this.selectedSpace!;
|
||||||
return `
|
return `
|
||||||
<div class="nav">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="spaces">Back</button>
|
<button class="rapp-nav__back" data-back="spaces">\u2190 Spaces</button>
|
||||||
<span class="nav-title">${this.esc(s.name)} — Proposals</span>
|
<span class="rapp-nav__title">${this.esc(s.name)} — Proposals</span>
|
||||||
</div>
|
</div>
|
||||||
${this.proposals.length === 0 ? '<div class="empty">No proposals yet.</div>' : ""}
|
${this.proposals.length === 0 ? '<div class="empty">No proposals yet.</div>' : ""}
|
||||||
${this.proposals.map((p) => `
|
${this.proposals.map((p) => `
|
||||||
|
|
@ -267,9 +263,9 @@ class FolkVoteDashboard extends HTMLElement {
|
||||||
private renderProposal(): string {
|
private renderProposal(): string {
|
||||||
const p = this.selectedProposal!;
|
const p = this.selectedProposal!;
|
||||||
return `
|
return `
|
||||||
<div class="nav">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="proposals">Back</button>
|
<button class="rapp-nav__back" data-back="proposals">\u2190 Proposals</button>
|
||||||
<span class="nav-title">${this.esc(p.title)}</span>
|
<span class="rapp-nav__title">${this.esc(p.title)}</span>
|
||||||
<span class="badge" style="background:${this.getStatusColor(p.status)}20;color:${this.getStatusColor(p.status)};margin-left:8px">${p.status}</span>
|
<span class="badge" style="background:${this.getStatusColor(p.status)}20;color:${this.getStatusColor(p.status)};margin-left:8px">${p.status}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card" style="cursor:default">
|
<div class="card" style="cursor:default">
|
||||||
|
|
|
||||||
|
|
@ -110,12 +110,12 @@ class FolkWorkBoard extends HTMLElement {
|
||||||
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
.header { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
|
.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
|
||||||
.nav-btn { padding: 6px 14px; border-radius: 6px; border: 1px solid #444; background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 13px; }
|
.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; text-decoration: none; }
|
||||||
.nav-btn:hover { border-color: #666; }
|
.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
|
||||||
.header-title { font-size: 18px; font-weight: 600; margin-left: 8px; flex: 1; }
|
.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.create-btn { padding: 8px 16px; border-radius: 8px; border: none; background: #6366f1; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
.rapp-nav__btn { padding: 6px 14px; border-radius: 6px; border: none; background: #4f46e5; color: #fff; font-weight: 600; cursor: pointer; font-size: 13px; }
|
||||||
.create-btn:hover { background: #4f46e5; }
|
.rapp-nav__btn:hover { background: #6366f1; }
|
||||||
|
|
||||||
.workspace-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
|
.workspace-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
|
||||||
.workspace-card {
|
.workspace-card {
|
||||||
|
|
@ -160,9 +160,9 @@ class FolkWorkBoard extends HTMLElement {
|
||||||
|
|
||||||
private renderList(): string {
|
private renderList(): string {
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<span class="header-title">Workspaces</span>
|
<span class="rapp-nav__title">Workspaces</span>
|
||||||
<button class="create-btn" id="create-ws">+ New Workspace</button>
|
<button class="rapp-nav__btn" id="create-ws">+ New Workspace</button>
|
||||||
</div>
|
</div>
|
||||||
${this.workspaces.length > 0 ? `<div class="workspace-grid">
|
${this.workspaces.length > 0 ? `<div class="workspace-grid">
|
||||||
${this.workspaces.map(ws => `
|
${this.workspaces.map(ws => `
|
||||||
|
|
@ -180,10 +180,10 @@ class FolkWorkBoard extends HTMLElement {
|
||||||
|
|
||||||
private renderBoard(): string {
|
private renderBoard(): string {
|
||||||
return `
|
return `
|
||||||
<div class="header">
|
<div class="rapp-nav">
|
||||||
<button class="nav-btn" data-back="list">\u2190 Back</button>
|
<button class="rapp-nav__back" data-back="list">\u2190 Workspaces</button>
|
||||||
<span class="header-title">${this.esc(this.workspaceSlug)}</span>
|
<span class="rapp-nav__title">${this.esc(this.workspaceSlug)}</span>
|
||||||
<button class="create-btn" id="create-task">+ New Task</button>
|
<button class="rapp-nav__btn" id="create-task">+ New Task</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="board">
|
<div class="board">
|
||||||
${this.statuses.map(status => {
|
${this.statuses.map(status => {
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,89 @@ body {
|
||||||
gap: 0;
|
gap: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Shared in-app navigation bar (used by module components) ── */
|
||||||
|
|
||||||
|
.rapp-nav {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__back {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
background: transparent;
|
||||||
|
color: #94a3b8;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.15s, border-color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__back:hover {
|
||||||
|
color: #e2e8f0;
|
||||||
|
border-color: rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #e2e8f0;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__btn {
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: none;
|
||||||
|
background: #4f46e5;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__btn:hover {
|
||||||
|
background: #6366f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__btn--secondary {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid rgba(255,255,255,0.15);
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__btn--secondary:hover {
|
||||||
|
border-color: rgba(255,255,255,0.3);
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rapp-nav__badge {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fbbf24;
|
||||||
|
background: rgba(251,191,36,0.15);
|
||||||
|
border: 1px solid rgba(251,191,36,0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Mobile adjustments ── */
|
/* ── Mobile adjustments ── */
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue