mirror of
https://codeberg.org/likwid/likwid.git
synced 2026-02-09 21:13:09 +00:00
873 lines
23 KiB
Text
873 lines
23 KiB
Text
|
|
---
|
||
|
|
import PublicLayout from '../layouts/PublicLayout.astro';
|
||
|
|
import { API_BASE } from '../lib/api';
|
||
|
|
---
|
||
|
|
|
||
|
|
<PublicLayout title="Demo" description="Explore Likwid's governance features with a live demo instance featuring pre-populated communities and real governance history.">
|
||
|
|
<article class="demo-page">
|
||
|
|
<header class="page-header">
|
||
|
|
<span class="page-label">Live Demo</span>
|
||
|
|
<h1>Experience Governance in Action</h1>
|
||
|
|
<p class="lead">
|
||
|
|
A governance platform cannot be understood from screenshots or empty interfaces.
|
||
|
|
Explore a live instance with real communities, ongoing decisions, and visible history.
|
||
|
|
</p>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
<section class="demo-intro">
|
||
|
|
<div class="intro-content">
|
||
|
|
<h2>Why a Demo Instance?</h2>
|
||
|
|
<p>
|
||
|
|
Governance only makes sense when it has context. Decisions need history.
|
||
|
|
Delegation needs visible relationships. Moderation needs traceable events.
|
||
|
|
An empty system communicates nothing.
|
||
|
|
</p>
|
||
|
|
<p>
|
||
|
|
Our demo instance includes pre-seeded communities with:
|
||
|
|
</p>
|
||
|
|
<ul>
|
||
|
|
<li>Past, ongoing, and scheduled decisions</li>
|
||
|
|
<li>Active delegation networks</li>
|
||
|
|
<li>Visible moderation history</li>
|
||
|
|
<li>Multiple voting methods in use</li>
|
||
|
|
<li>Real governance narratives, not random data</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="demo-communities">
|
||
|
|
<h2>Demo Communities</h2>
|
||
|
|
<p class="section-intro">
|
||
|
|
Explore different types of organizations and see how they use Likwid for governance.
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<div class="community-cards" id="community-cards">
|
||
|
|
<div class="community-card">
|
||
|
|
<div class="card-header">
|
||
|
|
<h3>Aurora Framework</h3>
|
||
|
|
<span class="card-tag">Open Source Project</span>
|
||
|
|
</div>
|
||
|
|
<p>
|
||
|
|
A fictional open source project demonstrating technical decision-making.
|
||
|
|
See RFC processes, feature prioritization, and maintainer elections using
|
||
|
|
Schulze voting and liquid delegation.
|
||
|
|
</p>
|
||
|
|
<div class="card-stats" id="stats-aurora">
|
||
|
|
<span class="loading-text">Loading...</span>
|
||
|
|
</div>
|
||
|
|
<a href="/communities/aurora" class="card-link">Explore Aurora →</a>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="community-card">
|
||
|
|
<div class="card-header">
|
||
|
|
<h3>Civic Commons Network</h3>
|
||
|
|
<span class="card-tag">Political Movement</span>
|
||
|
|
</div>
|
||
|
|
<p>
|
||
|
|
A grassroots civic organization showing policy development and delegate assemblies.
|
||
|
|
Observe quadratic voting for priority setting and transparent moderation
|
||
|
|
for community standards.
|
||
|
|
</p>
|
||
|
|
<div class="card-stats" id="stats-civic-commons">
|
||
|
|
<span class="loading-text">Loading...</span>
|
||
|
|
</div>
|
||
|
|
<a href="/communities/civic-commons" class="card-link">Explore Civic Commons →</a>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="community-card">
|
||
|
|
<div class="card-header">
|
||
|
|
<h3>Regional Makers Collective</h3>
|
||
|
|
<span class="card-tag">Federation</span>
|
||
|
|
</div>
|
||
|
|
<p>
|
||
|
|
A network of local chapters demonstrating federated governance.
|
||
|
|
See cross-community coordination, shared resources decisions,
|
||
|
|
and chapter autonomy in practice.
|
||
|
|
</p>
|
||
|
|
<div class="card-stats" id="stats-makers">
|
||
|
|
<span class="loading-text">Loading...</span>
|
||
|
|
</div>
|
||
|
|
<a href="/communities/makers" class="card-link">Explore Makers →</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="demo-access">
|
||
|
|
<h2>How to Explore</h2>
|
||
|
|
|
||
|
|
<div class="access-modes">
|
||
|
|
<div class="access-mode">
|
||
|
|
<div class="mode-icon">👁️</div>
|
||
|
|
<h4>Browse Freely</h4>
|
||
|
|
<p>
|
||
|
|
Navigate communities, read proposals, view voting results, and explore
|
||
|
|
delegation networks without any account. Full read access is public.
|
||
|
|
</p>
|
||
|
|
<a href="/communities" class="mode-link">Browse Communities →</a>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="access-mode">
|
||
|
|
<div class="mode-icon">🧪</div>
|
||
|
|
<h4>Demo Accounts</h4>
|
||
|
|
<p>
|
||
|
|
Click a demo account below to log in instantly and experience participation:
|
||
|
|
vote on proposals, create delegations, and see the member experience firsthand.
|
||
|
|
</p>
|
||
|
|
<div class="demo-accounts">
|
||
|
|
<button class="demo-login-btn" data-username="contributor">
|
||
|
|
<div class="btn-icon">👤</div>
|
||
|
|
<div class="btn-info">
|
||
|
|
<strong>Contributor</strong>
|
||
|
|
<span>Standard member - can vote and participate</span>
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
<button class="demo-login-btn" data-username="moderator">
|
||
|
|
<div class="btn-icon">🛡️</div>
|
||
|
|
<div class="btn-info">
|
||
|
|
<strong>Moderator</strong>
|
||
|
|
<span>Can moderate content and view logs</span>
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
<button class="demo-login-btn" data-username="observer">
|
||
|
|
<div class="btn-icon">👁️</div>
|
||
|
|
<div class="btn-info">
|
||
|
|
<strong>Observer</strong>
|
||
|
|
<span>Read-only access to explore</span>
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
<p class="demo-hint">All demo accounts use password: <code>demo123</code></p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="demo-notice">
|
||
|
|
<h4>Demo Reset Notice</h4>
|
||
|
|
<p>
|
||
|
|
The demo instance resets periodically to maintain a known state.
|
||
|
|
Any changes you make will be reverted. This ensures every visitor
|
||
|
|
experiences meaningful governance data, not accumulated noise.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="demo-journey">
|
||
|
|
<h2>Suggested Exploration Path</h2>
|
||
|
|
|
||
|
|
<div class="journey-steps">
|
||
|
|
<div class="journey-step">
|
||
|
|
<div class="step-number">1</div>
|
||
|
|
<div class="step-content">
|
||
|
|
<h4>Browse a Community</h4>
|
||
|
|
<p>Start with Aurora Framework. See the community overview, active members, and governance structure.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="journey-step">
|
||
|
|
<div class="step-number">2</div>
|
||
|
|
<div class="step-content">
|
||
|
|
<h4>Read a Completed Decision</h4>
|
||
|
|
<p>Find a closed proposal. See the deliberation history, voting results, and how the outcome was reached.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="journey-step">
|
||
|
|
<div class="step-number">3</div>
|
||
|
|
<div class="step-content">
|
||
|
|
<h4>Explore Delegations</h4>
|
||
|
|
<p>View the delegation network. See who trusts whom on which topics and how votes flow.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="journey-step">
|
||
|
|
<div class="step-number">4</div>
|
||
|
|
<div class="step-content">
|
||
|
|
<h4>Check the Moderation Log</h4>
|
||
|
|
<p>See transparent moderation in action. Every action has a reason, a rule reference, and accountability.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="journey-step">
|
||
|
|
<div class="step-number">5</div>
|
||
|
|
<div class="step-content">
|
||
|
|
<h4>Cast a Vote</h4>
|
||
|
|
<p>Log in with a demo account and vote on an active proposal. Experience different voting methods.</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="demo-cta">
|
||
|
|
<h2>Ready to Explore?</h2>
|
||
|
|
<p>
|
||
|
|
The demo is live and waiting. No registration required to browse.
|
||
|
|
Use demo accounts to participate.
|
||
|
|
</p>
|
||
|
|
<div class="cta-buttons">
|
||
|
|
<a href="/communities" class="btn-primary btn-large">Enter the Demo</a>
|
||
|
|
<a href="/login" class="btn-secondary">Sign In with Demo Account</a>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<section class="demo-next">
|
||
|
|
<h2>What's Next?</h2>
|
||
|
|
<div class="next-options">
|
||
|
|
<a href="/about" class="next-card">
|
||
|
|
<h4>Learn More</h4>
|
||
|
|
<p>Understand what Likwid is, who it's for, and how it works.</p>
|
||
|
|
</a>
|
||
|
|
<a href="/manifesto" class="next-card">
|
||
|
|
<h4>Read the Manifesto</h4>
|
||
|
|
<p>Explore the technical and political vision behind Likwid.</p>
|
||
|
|
</a>
|
||
|
|
<a href="/docs" class="next-card">
|
||
|
|
<h4>Documentation</h4>
|
||
|
|
<p>Technical guides for deployment, configuration, and development.</p>
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
</article>
|
||
|
|
</PublicLayout>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
.demo-page {
|
||
|
|
max-width: 1000px;
|
||
|
|
margin: 0 auto;
|
||
|
|
padding: 0 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header {
|
||
|
|
text-align: center;
|
||
|
|
padding: 3rem 0 3.5rem;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-label {
|
||
|
|
display: inline-block;
|
||
|
|
font-size: 0.6875rem;
|
||
|
|
font-weight: 600;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.1em;
|
||
|
|
color: var(--color-success);
|
||
|
|
background: var(--color-success-muted);
|
||
|
|
padding: 0.375rem 1rem;
|
||
|
|
border-radius: 999px;
|
||
|
|
margin-bottom: 1.25rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header h1 {
|
||
|
|
font-size: 2.25rem;
|
||
|
|
font-weight: 700;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
letter-spacing: -0.02em;
|
||
|
|
}
|
||
|
|
|
||
|
|
.lead {
|
||
|
|
font-size: 1.25rem;
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
max-width: 650px;
|
||
|
|
margin: 0 auto;
|
||
|
|
line-height: 1.6;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Intro Section */
|
||
|
|
.demo-intro {
|
||
|
|
padding: 3rem 0;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.intro-content h2 {
|
||
|
|
font-size: 1.75rem;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.intro-content p {
|
||
|
|
color: var(--color-text);
|
||
|
|
line-height: 1.7;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.intro-content ul {
|
||
|
|
list-style: none;
|
||
|
|
padding: 0;
|
||
|
|
margin: 1.5rem 0 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.intro-content li {
|
||
|
|
padding: 0.5rem 0 0.5rem 1.5rem;
|
||
|
|
position: relative;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
.intro-content li::before {
|
||
|
|
content: "✓";
|
||
|
|
position: absolute;
|
||
|
|
left: 0;
|
||
|
|
color: var(--color-success);
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Communities Section */
|
||
|
|
.demo-communities {
|
||
|
|
padding: 3rem 0;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-communities h2 {
|
||
|
|
font-size: 1.75rem;
|
||
|
|
text-align: center;
|
||
|
|
margin-bottom: 0.75rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-intro {
|
||
|
|
text-align: center;
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.community-cards {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(3, 1fr);
|
||
|
|
gap: 1.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 900px) {
|
||
|
|
.community-cards {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.community-card {
|
||
|
|
background: var(--color-surface);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: var(--radius-lg);
|
||
|
|
padding: 1.5rem;
|
||
|
|
transition: all var(--motion-normal) var(--easing-standard);
|
||
|
|
}
|
||
|
|
|
||
|
|
.community-card:hover {
|
||
|
|
border-color: var(--color-border-hover);
|
||
|
|
transform: translateY(-2px);
|
||
|
|
box-shadow: var(--shadow-md);
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-header {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 0.5rem;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-header h3 {
|
||
|
|
font-size: 1.25rem;
|
||
|
|
margin: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-tag {
|
||
|
|
display: inline-block;
|
||
|
|
font-size: 0.75rem;
|
||
|
|
padding: 0.25rem 0.75rem;
|
||
|
|
background: var(--color-primary-muted);
|
||
|
|
color: var(--color-primary);
|
||
|
|
border-radius: 999px;
|
||
|
|
font-weight: 500;
|
||
|
|
width: fit-content;
|
||
|
|
}
|
||
|
|
|
||
|
|
.community-card p {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
font-size: 0.9375rem;
|
||
|
|
line-height: 1.5;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-stats {
|
||
|
|
display: flex;
|
||
|
|
gap: 1rem;
|
||
|
|
padding-top: 1rem;
|
||
|
|
border-top: 1px solid var(--color-border);
|
||
|
|
font-size: 0.8125rem;
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Access Section */
|
||
|
|
.demo-access {
|
||
|
|
padding: 3rem 0;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-access h2 {
|
||
|
|
font-size: 1.75rem;
|
||
|
|
text-align: center;
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.access-modes {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(2, 1fr);
|
||
|
|
gap: 2rem;
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 768px) {
|
||
|
|
.access-modes {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.access-mode {
|
||
|
|
background: var(--color-surface);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: var(--radius-lg);
|
||
|
|
padding: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.mode-icon {
|
||
|
|
font-size: 2rem;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.access-mode h4 {
|
||
|
|
font-size: 1.25rem;
|
||
|
|
margin-bottom: 0.75rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.access-mode p {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
line-height: 1.6;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.mode-link {
|
||
|
|
display: inline-block;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-accounts {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 0.75rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 1rem;
|
||
|
|
width: 100%;
|
||
|
|
padding: 1rem 1.25rem;
|
||
|
|
background: var(--color-bg-alt);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all var(--motion-fast) var(--easing-standard);
|
||
|
|
text-align: left;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn:hover {
|
||
|
|
border-color: var(--color-primary);
|
||
|
|
background: var(--color-primary-muted);
|
||
|
|
transform: translateY(-2px);
|
||
|
|
box-shadow: 0 4px 12px rgba(129, 140, 248, 0.15);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn:active {
|
||
|
|
transform: translateY(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn .btn-icon {
|
||
|
|
font-size: 1.5rem;
|
||
|
|
width: 2.5rem;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn .btn-info {
|
||
|
|
flex: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn .btn-info strong {
|
||
|
|
display: block;
|
||
|
|
font-size: 1rem;
|
||
|
|
color: var(--color-text);
|
||
|
|
margin-bottom: 0.25rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn .btn-info span {
|
||
|
|
font-size: 0.8125rem;
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-login-btn.loading {
|
||
|
|
opacity: 0.7;
|
||
|
|
pointer-events: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-hint {
|
||
|
|
font-size: 0.8125rem;
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
text-align: center;
|
||
|
|
margin-top: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-hint code {
|
||
|
|
background: var(--color-bg-alt);
|
||
|
|
padding: 0.125rem 0.5rem;
|
||
|
|
border-radius: var(--radius-sm);
|
||
|
|
font-family: monospace;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-notice {
|
||
|
|
background: var(--color-warning-muted);
|
||
|
|
border: 1px solid var(--color-warning);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
padding: 1.5rem;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-notice h4 {
|
||
|
|
font-size: 1rem;
|
||
|
|
margin-bottom: 0.5rem;
|
||
|
|
color: var(--color-warning);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-notice p {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
font-size: 0.9375rem;
|
||
|
|
margin: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journey Section */
|
||
|
|
.demo-journey {
|
||
|
|
padding: 3rem 0;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-journey h2 {
|
||
|
|
font-size: 1.75rem;
|
||
|
|
text-align: center;
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.journey-steps {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.journey-step {
|
||
|
|
display: flex;
|
||
|
|
gap: 1.5rem;
|
||
|
|
align-items: flex-start;
|
||
|
|
padding: 1.5rem;
|
||
|
|
background: var(--color-surface);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
}
|
||
|
|
|
||
|
|
.step-number {
|
||
|
|
width: 36px;
|
||
|
|
height: 36px;
|
||
|
|
background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
|
||
|
|
color: var(--color-on-primary);
|
||
|
|
border-radius: 50%;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
font-weight: 700;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
flex-shrink: 0;
|
||
|
|
box-shadow: 0 2px 8px rgba(129, 140, 248, 0.25);
|
||
|
|
}
|
||
|
|
|
||
|
|
.step-content h4 {
|
||
|
|
font-size: 1rem;
|
||
|
|
margin-bottom: 0.25rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.step-content p {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
font-size: 0.9375rem;
|
||
|
|
margin: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* CTA Section */
|
||
|
|
.demo-cta {
|
||
|
|
text-align: center;
|
||
|
|
padding: 4rem 0;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-cta h2 {
|
||
|
|
font-size: 2rem;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-cta p {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.cta-buttons {
|
||
|
|
display: flex;
|
||
|
|
gap: 1rem;
|
||
|
|
justify-content: center;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-primary {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
background: var(--color-primary);
|
||
|
|
color: var(--color-text-inverse);
|
||
|
|
padding: 0.875rem 1.75rem;
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
font-weight: 600;
|
||
|
|
font-size: 0.9375rem;
|
||
|
|
transition: all var(--motion-fast) var(--easing-standard);
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-primary:hover {
|
||
|
|
background: var(--color-primary-hover);
|
||
|
|
color: var(--color-text-inverse);
|
||
|
|
transform: translateY(-2px);
|
||
|
|
box-shadow: 0 8px 24px rgba(129, 140, 248, 0.3);
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-primary.btn-large {
|
||
|
|
padding: 1rem 2.5rem;
|
||
|
|
font-size: 1.125rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-secondary {
|
||
|
|
display: inline-block;
|
||
|
|
background: transparent;
|
||
|
|
color: var(--color-text);
|
||
|
|
padding: 0.875rem 2rem;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
font-weight: 500;
|
||
|
|
transition: all var(--motion-fast) var(--easing-standard);
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-secondary:hover {
|
||
|
|
border-color: var(--color-primary);
|
||
|
|
color: var(--color-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Next Section */
|
||
|
|
.demo-next {
|
||
|
|
padding: 3rem 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-next h2 {
|
||
|
|
font-size: 1.75rem;
|
||
|
|
text-align: center;
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.next-options {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(3, 1fr);
|
||
|
|
gap: 1.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 768px) {
|
||
|
|
.next-options {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.next-card {
|
||
|
|
display: block;
|
||
|
|
padding: 1.5rem;
|
||
|
|
background: var(--color-surface);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
text-decoration: none;
|
||
|
|
transition: all var(--motion-fast) var(--easing-standard);
|
||
|
|
}
|
||
|
|
|
||
|
|
.next-card:hover {
|
||
|
|
border-color: var(--color-primary);
|
||
|
|
transform: translateY(-2px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.next-card h4 {
|
||
|
|
font-size: 1.125rem;
|
||
|
|
color: var(--color-text);
|
||
|
|
margin-bottom: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.next-card p {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
font-size: 0.875rem;
|
||
|
|
margin: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-link {
|
||
|
|
display: inline-block;
|
||
|
|
margin-top: 1rem;
|
||
|
|
font-weight: 500;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
color: var(--color-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-link:hover {
|
||
|
|
text-decoration: underline;
|
||
|
|
}
|
||
|
|
|
||
|
|
.loading-text {
|
||
|
|
color: var(--color-text-muted);
|
||
|
|
font-style: italic;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-status-banner {
|
||
|
|
background: var(--color-success-muted);
|
||
|
|
border: 1px solid var(--color-success);
|
||
|
|
border-radius: var(--radius-md);
|
||
|
|
padding: 1rem 1.5rem;
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-status-banner.inactive {
|
||
|
|
background: var(--color-warning-muted);
|
||
|
|
border-color: var(--color-warning);
|
||
|
|
}
|
||
|
|
|
||
|
|
.demo-status-banner p {
|
||
|
|
margin: 0;
|
||
|
|
font-size: 0.9375rem;
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
|
||
|
|
<script define:vars={{ API_BASE }}>
|
||
|
|
async function loadDemoData() {
|
||
|
|
try {
|
||
|
|
// Fetch demo status
|
||
|
|
const statusRes = await fetch(API_BASE + '/api/demo/status');
|
||
|
|
const status = await statusRes.json();
|
||
|
|
|
||
|
|
// Update demo status indicator if needed
|
||
|
|
const statusBanner = document.getElementById('demo-status');
|
||
|
|
if (statusBanner) {
|
||
|
|
if (status.demo_mode) {
|
||
|
|
statusBanner.innerHTML = '<p>✓ Demo mode is active. Explore freely!</p>';
|
||
|
|
statusBanner.classList.remove('inactive');
|
||
|
|
} else {
|
||
|
|
statusBanner.innerHTML = '<p>Demo mode is not currently enabled on this instance.</p>';
|
||
|
|
statusBanner.classList.add('inactive');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fetch communities data
|
||
|
|
const commRes = await fetch(API_BASE + '/api/demo/communities');
|
||
|
|
const commData = await commRes.json();
|
||
|
|
|
||
|
|
if (commData.communities && commData.communities.length > 0) {
|
||
|
|
// Map slugs to stat element IDs
|
||
|
|
const slugToId = {
|
||
|
|
'aurora': 'stats-aurora',
|
||
|
|
'civic-commons': 'stats-civic-commons',
|
||
|
|
'makers': 'stats-makers'
|
||
|
|
};
|
||
|
|
|
||
|
|
commData.communities.forEach(function(comm) {
|
||
|
|
const statsEl = document.getElementById(slugToId[comm.slug]);
|
||
|
|
if (statsEl) {
|
||
|
|
statsEl.innerHTML = '<span>' + comm.member_count + ' members</span><span>' + comm.proposal_count + ' proposals</span>';
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.log('Demo API not available:', error.message);
|
||
|
|
// Show fallback stats
|
||
|
|
['stats-aurora', 'stats-civic-commons', 'stats-makers'].forEach(function(id) {
|
||
|
|
const el = document.getElementById(id);
|
||
|
|
if (el) {
|
||
|
|
el.innerHTML = '<span>View community for details</span>';
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Demo login handler
|
||
|
|
async function handleDemoLogin(username) {
|
||
|
|
const btn = document.querySelector('[data-username="' + username + '"]');
|
||
|
|
if (btn) {
|
||
|
|
btn.classList.add('loading');
|
||
|
|
btn.querySelector('.btn-info span').textContent = 'Logging in...';
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const response = await fetch(API_BASE + '/api/auth/login', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
},
|
||
|
|
body: JSON.stringify({
|
||
|
|
username: username,
|
||
|
|
password: 'demo123'
|
||
|
|
}),
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
throw new Error('Login failed');
|
||
|
|
}
|
||
|
|
|
||
|
|
const data = await response.json();
|
||
|
|
|
||
|
|
// Store token in localStorage (use 'token' to match rest of app)
|
||
|
|
localStorage.setItem('token', data.token);
|
||
|
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||
|
|
|
||
|
|
// Update button to show success
|
||
|
|
if (btn) {
|
||
|
|
btn.querySelector('.btn-info span').textContent = 'Success! Redirecting...';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Redirect to dashboard or communities
|
||
|
|
setTimeout(() => {
|
||
|
|
window.location.href = '/communities';
|
||
|
|
}, 500);
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Demo login failed:', error);
|
||
|
|
if (btn) {
|
||
|
|
btn.classList.remove('loading');
|
||
|
|
btn.querySelector('.btn-info span').textContent = 'Login failed - try again';
|
||
|
|
setTimeout(() => {
|
||
|
|
// Reset button text
|
||
|
|
const texts = {
|
||
|
|
'contributor': 'Standard member - can vote and participate',
|
||
|
|
'moderator': 'Can moderate content and view logs',
|
||
|
|
'observer': 'Read-only access to explore'
|
||
|
|
};
|
||
|
|
btn.querySelector('.btn-info span').textContent = texts[username] || '';
|
||
|
|
}, 2000);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Attach click handlers to demo login buttons
|
||
|
|
function setupDemoLoginButtons() {
|
||
|
|
var buttons = document.querySelectorAll('.demo-login-btn');
|
||
|
|
for (var i = 0; i < buttons.length; i++) {
|
||
|
|
(function(btn) {
|
||
|
|
btn.addEventListener('click', function() {
|
||
|
|
var username = btn.dataset.username;
|
||
|
|
if (username) {
|
||
|
|
handleDemoLogin(username);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
})(buttons[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Load on page ready
|
||
|
|
if (document.readyState === 'loading') {
|
||
|
|
document.addEventListener('DOMContentLoaded', function() {
|
||
|
|
loadDemoData();
|
||
|
|
setupDemoLoginButtons();
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
loadDemoData();
|
||
|
|
setupDemoLoginButtons();
|
||
|
|
}
|
||
|
|
</script>
|