mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 19:30:38 +08:00
Redesign the How it works page
Rework the /principles page from a vertical slide presentation into a two-column layout.
This commit is contained in:
@@ -1,22 +1,30 @@
|
||||
<script lang="ts">
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import Meta from "@app/marketing/Meta.svelte";
|
||||
import PrincipleFigure from "@app/marketing/PrincipleFigure.svelte";
|
||||
|
||||
type Principle = {
|
||||
id: string;
|
||||
kicker: string;
|
||||
kickerMuted?: boolean;
|
||||
title: string;
|
||||
body?: string;
|
||||
};
|
||||
|
||||
const principles: Principle[] = [
|
||||
{ id: "intro", kicker: "The Radicle Protocol", title: "How it works" },
|
||||
{
|
||||
id: "status-quo",
|
||||
kicker: "The Status Quo",
|
||||
kicker: "Centralized platforms",
|
||||
kickerMuted: true,
|
||||
title: "Code lives on someone else’s server",
|
||||
body: "Your issues, patches and identity are controlled by the platform.",
|
||||
},
|
||||
{
|
||||
id: "nodes",
|
||||
kicker: "Radicle",
|
||||
title: "Everyone runs a node",
|
||||
body: "No central server. Each node hosts and shares Git repositories directly with peers.",
|
||||
},
|
||||
{ id: "nodes", kicker: "Radicle", title: "Everyone runs a node" },
|
||||
{
|
||||
id: "identity",
|
||||
kicker: "Identity",
|
||||
@@ -31,38 +39,31 @@
|
||||
id: "trust",
|
||||
kicker: "Trust",
|
||||
title: "Every change is cryptographically signed",
|
||||
body: "Repositories are self-certifying. Anyone can verify authenticity without trusting a central authority.",
|
||||
},
|
||||
{
|
||||
id: "collaboration",
|
||||
kicker: "Collaboration",
|
||||
title: "Issues and patches live inside the repo",
|
||||
body: "Collaborative Objects are local-first, user-owned and signed, just like your code.",
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.principles {
|
||||
--node-neutral: var(--color-text-secondary);
|
||||
--node-blue: var(--color-accent-blue-500);
|
||||
--node-green: var(--color-accent-green-600);
|
||||
--node-purple: var(--color-accent-purple-500);
|
||||
--node-amber: var(--color-semantic-amber-500);
|
||||
--mesh-line: var(--color-border-strong);
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
.page-title {
|
||||
max-width: 40rem;
|
||||
}
|
||||
|
||||
.principle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
gap: 1.5rem;
|
||||
gap: 3rem;
|
||||
padding: 4rem 0;
|
||||
}
|
||||
|
||||
@@ -70,9 +71,16 @@
|
||||
border-top: 1px solid var(--color-border-subtle);
|
||||
}
|
||||
|
||||
.principle-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
gap: 1.25rem;
|
||||
max-width: 34rem;
|
||||
}
|
||||
|
||||
.principle-kicker {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
color: var(--color-accent-blue-500);
|
||||
}
|
||||
|
||||
@@ -83,134 +91,15 @@
|
||||
.principle-title {
|
||||
font: var(--txt-bold-24);
|
||||
margin: 0;
|
||||
max-width: 42rem;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.principle-intro .principle-title {
|
||||
font: var(--txt-bold-32);
|
||||
letter-spacing: -0.02em;
|
||||
max-width: 30rem;
|
||||
}
|
||||
|
||||
.slide-lead {
|
||||
font: var(--txt-medium-22);
|
||||
.principle-body {
|
||||
font: var(--txt-medium-18);
|
||||
margin: 0;
|
||||
max-width: 34rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.slide-divider {
|
||||
width: 9rem;
|
||||
height: 2px;
|
||||
margin-top: 0.5rem;
|
||||
background: var(--color-accent-blue-500);
|
||||
border-radius: var(--border-radius-round);
|
||||
}
|
||||
|
||||
.slide-figure {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
width: 100%;
|
||||
max-width: 24rem;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.slide-caption {
|
||||
margin: 0;
|
||||
max-width: 38rem;
|
||||
}
|
||||
|
||||
/* Network diagram elements — theme-aware via design tokens. */
|
||||
.mesh-line {
|
||||
stroke: var(--mesh-line);
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.hub-dot circle {
|
||||
fill: var(--node-neutral);
|
||||
}
|
||||
|
||||
.hub-chip {
|
||||
fill: var(--color-surface-subtle);
|
||||
stroke: var(--color-border-mid);
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.hub-title {
|
||||
fill: var(--color-text-primary);
|
||||
font:
|
||||
600 15px Booton,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
.hub-sub {
|
||||
fill: var(--color-text-tertiary);
|
||||
font:
|
||||
400 12px "JetBrains Mono",
|
||||
monospace;
|
||||
}
|
||||
|
||||
.nd-blue {
|
||||
fill: var(--node-blue);
|
||||
}
|
||||
.nd-green {
|
||||
fill: var(--node-green);
|
||||
}
|
||||
.nd-purple {
|
||||
fill: var(--node-purple);
|
||||
}
|
||||
.nd-neutral {
|
||||
fill: var(--node-neutral);
|
||||
}
|
||||
|
||||
.gossip-ring {
|
||||
fill: none;
|
||||
stroke: var(--node-blue);
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
.gossip-ring-inner {
|
||||
stroke-opacity: 0.5;
|
||||
}
|
||||
.gossip-ring-outer {
|
||||
stroke-opacity: 0.25;
|
||||
}
|
||||
|
||||
.id-key {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
}
|
||||
.id-key-bg {
|
||||
fill: var(--node-blue);
|
||||
}
|
||||
.id-key-fg {
|
||||
stroke: var(--color-neutrals-opaque-light-0);
|
||||
stroke-width: 3;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
/* Identity */
|
||||
.did-key {
|
||||
max-width: 100%;
|
||||
padding: 0.6rem 1rem;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--border-radius-small);
|
||||
background: var(--color-surface-subtle);
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.did-prefix {
|
||||
max-width: 32rem;
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
.did-value {
|
||||
color: var(--color-code-strings);
|
||||
}
|
||||
|
||||
.id-points {
|
||||
list-style: none;
|
||||
@@ -223,7 +112,7 @@
|
||||
}
|
||||
.id-points li {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
align-items: flex-start;
|
||||
gap: 0.6rem;
|
||||
font: var(--txt-medium-16);
|
||||
}
|
||||
@@ -234,25 +123,14 @@
|
||||
.id-points .muted {
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
.dot {
|
||||
.id-points :global(svg) {
|
||||
flex: none;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: var(--border-radius-round);
|
||||
transform: translateY(-0.1em);
|
||||
}
|
||||
.dot-green {
|
||||
background: var(--node-green);
|
||||
}
|
||||
.dot-amber {
|
||||
background: var(--node-amber);
|
||||
}
|
||||
.dot-purple {
|
||||
background: var(--node-purple);
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
color: var(--node-green);
|
||||
transform: translateY(0.05em);
|
||||
}
|
||||
|
||||
/* Networking */
|
||||
.net-steps {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
@@ -274,110 +152,22 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Trust */
|
||||
.trust-figure {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
}
|
||||
.ref-card {
|
||||
text-align: left;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--border-radius-regular);
|
||||
background: var(--color-surface-subtle);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
.ref-head {
|
||||
color: var(--color-code-keywords);
|
||||
font-weight: 600;
|
||||
}
|
||||
.ref-row {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ref-row .hash {
|
||||
color: var(--color-code-strings);
|
||||
flex: none;
|
||||
}
|
||||
.ref-row .ref-path {
|
||||
color: var(--color-text-tertiary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.signed-badge {
|
||||
position: absolute;
|
||||
right: -0.25rem;
|
||||
bottom: -1.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.35rem 0.35rem 0.35rem 0.9rem;
|
||||
border-radius: var(--border-radius-round);
|
||||
background: var(--color-surface-canvas);
|
||||
}
|
||||
.signed-check {
|
||||
.principle-visual {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
background: var(--node-green);
|
||||
color: var(--color-neutrals-opaque-light-0);
|
||||
}
|
||||
|
||||
/* Collaboration */
|
||||
.repo-card {
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
text-align: left;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--border-radius-regular);
|
||||
background: var(--color-surface-subtle);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
.repo-head {
|
||||
color: var(--color-code-keywords);
|
||||
font-weight: 600;
|
||||
}
|
||||
.repo-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
.repo-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
background: var(--color-surface-mid);
|
||||
font: var(--txt-medium-16);
|
||||
}
|
||||
.repo-row strong {
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
.repo-meta {
|
||||
margin-left: auto;
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
@media (max-width: 56rem) {
|
||||
.principle {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
padding: 2.5rem 0;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
max-width: 18rem;
|
||||
.principle-visual {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.id-points {
|
||||
@@ -396,315 +186,68 @@
|
||||
|
||||
<main class="page-container principles">
|
||||
<header class="page-header">
|
||||
<h1 class="txt-bold-32">
|
||||
How it works. <span class="txt-color-tertiary">
|
||||
The core ideas behind Radicle.
|
||||
</span>
|
||||
<h1 class="page-title txt-bold-32">
|
||||
How it works.
|
||||
<br />
|
||||
<span class="txt-color-tertiary">The core ideas behind Radicle.</span>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
{#each principles as principle (principle.id)}
|
||||
<section class="principle" class:principle-intro={principle.id === "intro"}>
|
||||
<span
|
||||
class="principle-kicker txt-bold-14"
|
||||
class:muted={principle.kickerMuted}>
|
||||
{principle.kicker}
|
||||
</span>
|
||||
<h2 class="principle-title">{principle.title}</h2>
|
||||
<section class="principle">
|
||||
<div class="principle-text">
|
||||
<span
|
||||
class="principle-kicker txt-bold-14"
|
||||
class:muted={principle.kickerMuted}>
|
||||
{principle.kicker}
|
||||
</span>
|
||||
<h2 class="principle-title">{principle.title}</h2>
|
||||
|
||||
{#if principle.id === "intro"}
|
||||
<p class="slide-lead">
|
||||
A sovereign, peer-to-peer network for code collaboration
|
||||
</p>
|
||||
<span class="slide-divider"></span>
|
||||
{:else if principle.id === "status-quo"}
|
||||
<div class="slide-figure">
|
||||
<svg
|
||||
class="diagram"
|
||||
viewBox="0 0 360 300"
|
||||
fill="none"
|
||||
aria-hidden="true">
|
||||
<g class="mesh-line">
|
||||
<line x1="180" y1="150" x2="180" y2="36" />
|
||||
<line x1="180" y1="150" x2="300" y2="92" />
|
||||
<line x1="180" y1="150" x2="60" y2="92" />
|
||||
<line x1="180" y1="150" x2="300" y2="210" />
|
||||
<line x1="180" y1="150" x2="60" y2="210" />
|
||||
<line x1="180" y1="150" x2="180" y2="266" />
|
||||
</g>
|
||||
<g class="hub-dot">
|
||||
<circle cx="180" cy="36" r="9" />
|
||||
<circle cx="300" cy="92" r="9" />
|
||||
<circle cx="60" cy="92" r="9" />
|
||||
<circle cx="300" cy="210" r="9" />
|
||||
<circle cx="60" cy="210" r="9" />
|
||||
<circle cx="180" cy="266" r="9" />
|
||||
</g>
|
||||
<rect
|
||||
class="hub-chip"
|
||||
x="116"
|
||||
y="124"
|
||||
width="128"
|
||||
height="52"
|
||||
rx="10" />
|
||||
<text class="hub-title" x="180" y="147" text-anchor="middle">
|
||||
Central forge
|
||||
</text>
|
||||
<text class="hub-sub" x="180" y="166" text-anchor="middle">
|
||||
GitHub · GitLab
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="slide-caption txt-medium-18 txt-color-tertiary">
|
||||
Your issues, patches and identity are controlled by the platform.
|
||||
</p>
|
||||
{:else if principle.id === "nodes"}
|
||||
<div class="slide-figure">
|
||||
<svg
|
||||
class="diagram"
|
||||
viewBox="0 0 360 340"
|
||||
fill="none"
|
||||
aria-hidden="true">
|
||||
<g class="mesh-line">
|
||||
<line x1="180" y1="55" x2="274" y2="100" />
|
||||
<line x1="274" y1="100" x2="297" y2="202" />
|
||||
<line x1="297" y1="202" x2="232" y2="283" />
|
||||
<line x1="232" y1="283" x2="128" y2="283" />
|
||||
<line x1="128" y1="283" x2="63" y2="202" />
|
||||
<line x1="63" y1="202" x2="86" y2="100" />
|
||||
<line x1="86" y1="100" x2="180" y2="55" />
|
||||
<line x1="180" y1="55" x2="232" y2="283" />
|
||||
<line x1="274" y1="100" x2="128" y2="283" />
|
||||
<line x1="297" y1="202" x2="63" y2="202" />
|
||||
<line x1="180" y1="55" x2="297" y2="202" />
|
||||
<line x1="232" y1="283" x2="63" y2="202" />
|
||||
<line x1="128" y1="283" x2="86" y2="100" />
|
||||
</g>
|
||||
<circle
|
||||
class="nd-blue"
|
||||
cx="180"
|
||||
cy="55"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-green"
|
||||
cx="274"
|
||||
cy="100"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-purple"
|
||||
cx="297"
|
||||
cy="202"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-blue"
|
||||
cx="232"
|
||||
cy="283"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-green"
|
||||
cx="128"
|
||||
cy="283"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-purple"
|
||||
cx="63"
|
||||
cy="202"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-blue"
|
||||
cx="86"
|
||||
cy="100"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle class="nd-blue" cx="180" cy="55" r="9" />
|
||||
<circle class="nd-green" cx="274" cy="100" r="9" />
|
||||
<circle class="nd-purple" cx="297" cy="202" r="9" />
|
||||
<circle class="nd-blue" cx="232" cy="283" r="9" />
|
||||
<circle class="nd-green" cx="128" cy="283" r="9" />
|
||||
<circle class="nd-purple" cx="63" cy="202" r="9" />
|
||||
<circle class="nd-blue" cx="86" cy="100" r="9" />
|
||||
</svg>
|
||||
</div>
|
||||
<p class="slide-caption txt-medium-18 txt-color-tertiary">
|
||||
No central server. Each node hosts and shares Git repositories
|
||||
directly with peers.
|
||||
</p>
|
||||
{:else if principle.id === "identity"}
|
||||
<div class="slide-figure">
|
||||
<svg
|
||||
class="id-key"
|
||||
viewBox="0 0 64 64"
|
||||
fill="none"
|
||||
aria-hidden="true">
|
||||
<circle class="id-key-bg" cx="32" cy="32" r="24" />
|
||||
<g class="id-key-fg">
|
||||
<circle cx="26" cy="32" r="5.5" />
|
||||
<path d="M31 32 H44" />
|
||||
<path d="M40 32 V37" />
|
||||
<path d="M44 32 V37" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="did-key mono">
|
||||
<span class="did-prefix">did:key:</span>
|
||||
<span class="did-value">
|
||||
z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK
|
||||
</span>
|
||||
</div>
|
||||
<ul class="id-points">
|
||||
<li>
|
||||
<span class="dot dot-green"></span>
|
||||
<span>
|
||||
<strong>Generated offline</strong>
|
||||
<span class="muted">— no email, no account, no permission</span>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dot dot-green"></span>
|
||||
<span>
|
||||
<strong>Your public key is your Node ID</strong>
|
||||
<span class="muted">— the same across every device</span>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="dot dot-green"></span>
|
||||
<span>
|
||||
<strong>Sign every action</strong>
|
||||
<span class="muted">— so peers can verify it’s really you</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
{:else if principle.id === "networking"}
|
||||
<div class="slide-figure">
|
||||
<svg
|
||||
class="diagram"
|
||||
viewBox="0 0 360 360"
|
||||
fill="none"
|
||||
aria-hidden="true">
|
||||
<g class="mesh-line">
|
||||
<line x1="239" y1="73" x2="298" y2="175" />
|
||||
<line x1="298" y1="175" x2="239" y2="277" />
|
||||
<line x1="239" y1="277" x2="121" y2="277" />
|
||||
<line x1="121" y1="277" x2="62" y2="175" />
|
||||
<line x1="62" y1="175" x2="121" y2="73" />
|
||||
<line x1="121" y1="73" x2="239" y2="73" />
|
||||
<line x1="239" y1="73" x2="239" y2="277" />
|
||||
<line x1="298" y1="175" x2="121" y2="277" />
|
||||
<line x1="298" y1="175" x2="121" y2="73" />
|
||||
<line x1="239" y1="277" x2="62" y2="175" />
|
||||
<line x1="121" y1="277" x2="121" y2="73" />
|
||||
<line x1="62" y1="175" x2="239" y2="73" />
|
||||
</g>
|
||||
<circle
|
||||
class="gossip-ring gossip-ring-outer"
|
||||
cx="180"
|
||||
cy="175"
|
||||
r="84" />
|
||||
<circle
|
||||
class="gossip-ring gossip-ring-inner"
|
||||
cx="180"
|
||||
cy="175"
|
||||
r="48" />
|
||||
<circle class="nd-neutral" cx="239" cy="73" r="10" />
|
||||
<circle class="nd-neutral" cx="298" cy="175" r="10" />
|
||||
<circle class="nd-neutral" cx="239" cy="277" r="10" />
|
||||
<circle class="nd-neutral" cx="121" cy="277" r="10" />
|
||||
<circle class="nd-neutral" cx="62" cy="175" r="10" />
|
||||
<circle class="nd-neutral" cx="121" cy="73" r="10" />
|
||||
<circle
|
||||
class="nd-blue"
|
||||
cx="180"
|
||||
cy="175"
|
||||
r="22"
|
||||
fill-opacity="0.15" />
|
||||
<circle class="nd-blue" cx="180" cy="175" r="11" />
|
||||
</svg>
|
||||
</div>
|
||||
<ol class="net-steps">
|
||||
<li>
|
||||
<span class="num">1.</span>
|
||||
Announce updates over gossip
|
||||
</li>
|
||||
<li>
|
||||
<span class="num">2.</span>
|
||||
Replicate the data with Git’s own transfer protocol
|
||||
</li>
|
||||
</ol>
|
||||
{:else if principle.id === "trust"}
|
||||
<div class="slide-figure">
|
||||
<div class="trust-figure">
|
||||
<div class="ref-card mono">
|
||||
<div class="ref-head">refs/rad/sigrefs</div>
|
||||
<div class="ref-row">
|
||||
<span class="hash">9767b485c2aad1e2</span>
|
||||
<span class="ref-path">refs/heads/master</span>
|
||||
</div>
|
||||
<div class="ref-row">
|
||||
<span class="hash">f3eaa7454e3a4714</span>
|
||||
<span class="ref-path">refs/cobs/xyz.radicle.patch/…</span>
|
||||
</div>
|
||||
<div class="ref-row">
|
||||
<span class="hash">0590b78ee42b3908</span>
|
||||
<span class="ref-path">refs/cobs/xyz.radicle.issue/…</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="signed-badge">
|
||||
<span class="signed-label txt-bold-16">Signed</span>
|
||||
<span class="signed-check">
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
{#if principle.body}
|
||||
<p class="principle-body">{principle.body}</p>
|
||||
{/if}
|
||||
|
||||
{#if principle.id === "identity"}
|
||||
<ul class="id-points">
|
||||
<li>
|
||||
<Icon name="offline" />
|
||||
<span>
|
||||
<strong>Generated offline:</strong>
|
||||
<span class="muted">no email, no account, no permission</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="slide-caption txt-medium-18 txt-color-tertiary">
|
||||
Repositories are self-certifying — anyone can verify authenticity
|
||||
without trusting a central authority.
|
||||
</p>
|
||||
{:else if principle.id === "collaboration"}
|
||||
<div class="slide-figure">
|
||||
<div class="repo-card">
|
||||
<div class="repo-head mono">rad:z3gqcJUoA1n9…</div>
|
||||
<div class="repo-rows">
|
||||
<div class="repo-row">
|
||||
<span class="dot dot-green"></span>
|
||||
<strong>Code</strong>
|
||||
<span class="repo-meta mono">commits & branches</span>
|
||||
</div>
|
||||
<div class="repo-row">
|
||||
<span class="dot dot-amber"></span>
|
||||
<strong>Issues</strong>
|
||||
<span class="repo-meta mono">xyz.radicle.issue</span>
|
||||
</div>
|
||||
<div class="repo-row">
|
||||
<span class="dot dot-purple"></span>
|
||||
<strong>Patches</strong>
|
||||
<span class="repo-meta mono">xyz.radicle.patch</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="slide-caption txt-medium-18 txt-color-tertiary">
|
||||
Collaborative Objects are local-first, user-owned and signed — just
|
||||
like your code.
|
||||
</p>
|
||||
{/if}
|
||||
</li>
|
||||
<li>
|
||||
<Icon name="key" />
|
||||
<span>
|
||||
<strong>Your public key is your Node ID:</strong>
|
||||
<span class="muted">the same across every device</span>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<Icon name="badge" />
|
||||
<span>
|
||||
<strong>Sign every action:</strong>
|
||||
<span class="muted">so peers can verify it’s really you</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
{:else if principle.id === "networking"}
|
||||
<ol class="net-steps">
|
||||
<li>
|
||||
<span class="num">1.</span>
|
||||
Announce updates over gossip
|
||||
</li>
|
||||
<li>
|
||||
<span class="num">2.</span>
|
||||
Replicate the data with Git’s own transfer protocol
|
||||
</li>
|
||||
</ol>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="principle-visual">
|
||||
<PrincipleFigure id={principle.id} />
|
||||
</div>
|
||||
</section>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
+50
-26
@@ -289,38 +289,62 @@
|
||||
<line x1="232" y1="283" x2="63" y2="202" />
|
||||
<line x1="128" y1="283" x2="86" y2="100" />
|
||||
</g>
|
||||
<circle class="nd-blue" cx="180" cy="55" r="20" fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-green"
|
||||
cx="274"
|
||||
cy="100"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
class="nd-purple"
|
||||
cx="297"
|
||||
cy="202"
|
||||
r="20"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
<rect
|
||||
class="nd-blue"
|
||||
cx="232"
|
||||
cy="283"
|
||||
r="20"
|
||||
x="160"
|
||||
y="35"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
<rect
|
||||
class="nd-green"
|
||||
cx="128"
|
||||
cy="283"
|
||||
r="20"
|
||||
x="254"
|
||||
y="80"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<circle
|
||||
<rect
|
||||
class="nd-purple"
|
||||
cx="63"
|
||||
cy="202"
|
||||
r="20"
|
||||
x="277"
|
||||
y="182"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-blue"
|
||||
x="212"
|
||||
y="263"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-green"
|
||||
x="108"
|
||||
y="263"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-purple"
|
||||
x="43"
|
||||
y="182"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-blue"
|
||||
x="66"
|
||||
y="80"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<circle class="nd-blue" cx="86" cy="100" r="20" fill-opacity="0.13" />
|
||||
<circle class="nd-blue" cx="180" cy="55" r="9" />
|
||||
<circle class="nd-green" cx="274" cy="100" r="9" />
|
||||
<circle class="nd-purple" cx="297" cy="202" r="9" />
|
||||
|
||||
@@ -0,0 +1,849 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
|
||||
export let id: string;
|
||||
|
||||
const didPrefix = "z6Mkha";
|
||||
const didSuffix = "ta2doK";
|
||||
const didReal = `${didPrefix}…${didSuffix}`;
|
||||
const scrambleChars =
|
||||
"ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789";
|
||||
|
||||
let didValue = didReal;
|
||||
let generating = false;
|
||||
|
||||
function randomChar(): string {
|
||||
return scrambleChars.charAt(
|
||||
Math.floor(Math.random() * scrambleChars.length),
|
||||
);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (id !== "identity") return;
|
||||
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
|
||||
|
||||
const chars = didReal.split("");
|
||||
const scrambleTicks = 22;
|
||||
const cycle = scrambleTicks + 55;
|
||||
let tick = 0;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
tick = (tick + 1) % cycle;
|
||||
if (tick < scrambleTicks) {
|
||||
generating = true;
|
||||
const locked = Math.floor((tick / scrambleTicks) * chars.length);
|
||||
didValue = chars
|
||||
.map((ch, i) => (ch === "…" || i < locked ? ch : randomChar()))
|
||||
.join("");
|
||||
} else {
|
||||
generating = false;
|
||||
didValue = didReal;
|
||||
}
|
||||
}, 55);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.figure {
|
||||
--node-neutral: var(--color-text-secondary);
|
||||
--node-blue: var(--color-accent-blue-500);
|
||||
--node-green: var(--color-accent-green-600);
|
||||
--node-purple: var(--color-accent-purple-500);
|
||||
--node-amber: var(--color-semantic-amber-500);
|
||||
--mesh-line: var(--color-border-strong);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1.25rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
width: 100%;
|
||||
max-width: 22rem;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Network diagram elements — theme-aware via design tokens. */
|
||||
.mesh-line {
|
||||
stroke: var(--mesh-line);
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.hub-dot circle {
|
||||
fill: var(--node-neutral);
|
||||
}
|
||||
|
||||
/* Packets flowing along each spoke into the central forge, reinforcing
|
||||
that everything routes through one server. */
|
||||
.packet {
|
||||
fill: var(--color-text-tertiary);
|
||||
animation: forge-flow 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Colored packets exchanged directly between peers along the mesh edges. */
|
||||
.mesh-packet {
|
||||
fill: var(--c);
|
||||
}
|
||||
|
||||
@keyframes forge-flow {
|
||||
0%,
|
||||
100% {
|
||||
transform: translate(var(--dx), var(--dy));
|
||||
opacity: 0;
|
||||
}
|
||||
10% {
|
||||
transform: translate(var(--dx), var(--dy));
|
||||
opacity: 0.35;
|
||||
}
|
||||
30% {
|
||||
transform: translate(0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: translate(var(--dx), var(--dy));
|
||||
opacity: 0.35;
|
||||
}
|
||||
58% {
|
||||
transform: translate(var(--dx), var(--dy));
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.packet {
|
||||
animation: none;
|
||||
opacity: 0;
|
||||
}
|
||||
.id-key::before,
|
||||
.id-key::after {
|
||||
animation: none;
|
||||
opacity: 0;
|
||||
}
|
||||
.did-key::after {
|
||||
animation: none;
|
||||
}
|
||||
.gossip-ripple {
|
||||
animation: none;
|
||||
opacity: 0;
|
||||
}
|
||||
.ref-row {
|
||||
animation: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
.signed-check path {
|
||||
animation: none;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
.repo-row {
|
||||
animation: none;
|
||||
background-color: var(--color-surface-mid);
|
||||
}
|
||||
.repo-row .dot {
|
||||
animation: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.hub-chip {
|
||||
fill: var(--color-surface-subtle);
|
||||
stroke: var(--color-border-mid);
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.hub-title {
|
||||
fill: var(--color-text-primary);
|
||||
font:
|
||||
600 15px Booton,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
.hub-sub {
|
||||
fill: var(--color-text-tertiary);
|
||||
font:
|
||||
400 12px "JetBrains Mono",
|
||||
monospace;
|
||||
}
|
||||
|
||||
.nd-blue {
|
||||
fill: var(--node-blue);
|
||||
}
|
||||
.nd-green {
|
||||
fill: var(--node-green);
|
||||
}
|
||||
.nd-purple {
|
||||
fill: var(--node-purple);
|
||||
}
|
||||
.nd-neutral {
|
||||
fill: var(--node-neutral);
|
||||
}
|
||||
|
||||
/* Gossip announcements rippling out from the node to its peers. */
|
||||
.gossip-ripple {
|
||||
fill: none;
|
||||
stroke: var(--node-blue);
|
||||
stroke-width: 1.5;
|
||||
animation: gossip-out 3s ease-out infinite;
|
||||
}
|
||||
|
||||
@keyframes gossip-out {
|
||||
0% {
|
||||
r: 14px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
100% {
|
||||
r: 92px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Identity */
|
||||
.id-key {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
border-radius: var(--border-radius-round);
|
||||
background: var(--node-blue);
|
||||
color: var(--color-neutrals-opaque-light-0);
|
||||
}
|
||||
.id-key :global(svg) {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
/* Signal rings ping out from the key while it is generating, in sync with
|
||||
the key string being computed below. */
|
||||
.id-key::before,
|
||||
.id-key::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
border: 1.5px solid var(--node-blue);
|
||||
opacity: 0;
|
||||
}
|
||||
.id-key.generating::before,
|
||||
.id-key.generating::after {
|
||||
animation: id-ping 0.9s ease-out;
|
||||
}
|
||||
.id-key.generating::after {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
@keyframes id-ping {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 0.45;
|
||||
}
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(2.1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.did-key {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
padding: 0.6rem 1rem;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--border-radius-small);
|
||||
background: var(--color-surface-subtle);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Light sweep across the key string. A dark glint reads against the light
|
||||
surface; dark theme brightens instead. */
|
||||
.did-key {
|
||||
--shimmer-color: rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
:global(:root[data-theme="dark"]) .did-key {
|
||||
--shimmer-color: rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
.did-key::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
100deg,
|
||||
transparent 35%,
|
||||
var(--shimmer-color) 50%,
|
||||
transparent 65%
|
||||
);
|
||||
transform: translateX(-120%);
|
||||
animation: did-shimmer 4.5s ease-in-out infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes did-shimmer {
|
||||
0%,
|
||||
20% {
|
||||
transform: translateX(-120%);
|
||||
}
|
||||
70%,
|
||||
100% {
|
||||
transform: translateX(120%);
|
||||
}
|
||||
}
|
||||
.did-prefix {
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
.did-value {
|
||||
color: var(--color-code-strings);
|
||||
}
|
||||
|
||||
.dot {
|
||||
flex: none;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: var(--border-radius-round);
|
||||
}
|
||||
.dot-green {
|
||||
background: var(--node-green);
|
||||
}
|
||||
.dot-amber {
|
||||
background: var(--node-amber);
|
||||
}
|
||||
.dot-purple {
|
||||
background: var(--node-purple);
|
||||
}
|
||||
|
||||
/* Trust */
|
||||
.trust-figure {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 26rem;
|
||||
}
|
||||
.ref-card {
|
||||
text-align: left;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--border-radius-regular);
|
||||
background: var(--color-surface-subtle);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
.ref-head {
|
||||
color: var(--color-code-keywords);
|
||||
font-weight: 600;
|
||||
}
|
||||
.ref-row {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius-small);
|
||||
animation: ref-verify 4.5s ease-in-out infinite;
|
||||
}
|
||||
.ref-card .ref-row:nth-child(2) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
.ref-card .ref-row:nth-child(3) {
|
||||
animation-delay: 0.35s;
|
||||
}
|
||||
.ref-card .ref-row:nth-child(4) {
|
||||
animation-delay: 0.7s;
|
||||
}
|
||||
|
||||
/* Each signed ref highlights in turn, then the Signed check draws itself. */
|
||||
@keyframes ref-verify {
|
||||
0%,
|
||||
100% {
|
||||
background-color: transparent;
|
||||
}
|
||||
4% {
|
||||
background-color: color-mix(in srgb, var(--node-green) 18%, transparent);
|
||||
}
|
||||
16% {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
.ref-row .hash {
|
||||
color: var(--color-code-strings);
|
||||
flex: none;
|
||||
}
|
||||
.ref-row .ref-path {
|
||||
color: var(--color-text-tertiary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.signed-badge {
|
||||
position: absolute;
|
||||
right: -0.25rem;
|
||||
bottom: -1.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.35rem 0.35rem 0.35rem 0.9rem;
|
||||
border-radius: var(--border-radius-round);
|
||||
background: var(--color-surface-canvas);
|
||||
}
|
||||
.signed-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
background: var(--node-green);
|
||||
color: var(--color-neutrals-opaque-light-0);
|
||||
}
|
||||
.signed-check path {
|
||||
stroke-dasharray: 24;
|
||||
stroke-dashoffset: 0;
|
||||
animation: check-draw 4.5s ease-in-out infinite;
|
||||
}
|
||||
@keyframes check-draw {
|
||||
0%,
|
||||
42% {
|
||||
stroke-dashoffset: -24;
|
||||
}
|
||||
58%,
|
||||
92% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: -24;
|
||||
}
|
||||
}
|
||||
|
||||
/* Collaboration */
|
||||
.repo-card {
|
||||
width: 100%;
|
||||
max-width: 26rem;
|
||||
text-align: left;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border: 1px solid var(--color-border-subtle);
|
||||
border-radius: var(--border-radius-regular);
|
||||
background: var(--color-surface-subtle);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
.repo-head {
|
||||
color: var(--color-code-keywords);
|
||||
font-weight: 600;
|
||||
}
|
||||
.repo-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
.repo-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
background: var(--color-surface-mid);
|
||||
font: var(--txt-medium-16);
|
||||
animation: cob-row 3s ease-in-out infinite;
|
||||
}
|
||||
.repo-rows .repo-row:nth-child(1) {
|
||||
--row-accent: var(--node-green);
|
||||
}
|
||||
.repo-rows .repo-row:nth-child(2) {
|
||||
--row-accent: var(--node-amber);
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
.repo-rows .repo-row:nth-child(3) {
|
||||
--row-accent: var(--node-purple);
|
||||
animation-delay: 0.6s;
|
||||
}
|
||||
|
||||
/* Each object-type row lights up in sequence, its dot pulsing and the row
|
||||
briefly highlighting, a heartbeat of activity across the repo. */
|
||||
.repo-row .dot {
|
||||
animation: cob-pulse 3s ease-in-out infinite;
|
||||
}
|
||||
.repo-rows .repo-row:nth-child(2) .dot {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
.repo-rows .repo-row:nth-child(3) .dot {
|
||||
animation-delay: 0.6s;
|
||||
}
|
||||
@keyframes cob-pulse {
|
||||
0%,
|
||||
22%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
8% {
|
||||
transform: scale(1.5);
|
||||
}
|
||||
}
|
||||
@keyframes cob-row {
|
||||
0%,
|
||||
26%,
|
||||
100% {
|
||||
background-color: var(--color-surface-mid);
|
||||
}
|
||||
8% {
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
var(--row-accent) 16%,
|
||||
var(--color-surface-mid)
|
||||
);
|
||||
}
|
||||
}
|
||||
.repo-row strong {
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
.repo-meta {
|
||||
margin-left: auto;
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="figure">
|
||||
{#if id === "status-quo"}
|
||||
<svg class="diagram" viewBox="0 0 360 300" fill="none" aria-hidden="true">
|
||||
<g class="mesh-line">
|
||||
<line x1="180" y1="150" x2="180" y2="36" />
|
||||
<line x1="180" y1="150" x2="300" y2="92" />
|
||||
<line x1="180" y1="150" x2="60" y2="92" />
|
||||
<line x1="180" y1="150" x2="300" y2="210" />
|
||||
<line x1="180" y1="150" x2="60" y2="210" />
|
||||
<line x1="180" y1="150" x2="180" y2="266" />
|
||||
</g>
|
||||
<g class="forge-packets">
|
||||
<circle
|
||||
class="packet"
|
||||
cx="180"
|
||||
cy="150"
|
||||
r="3"
|
||||
style="--dx: 0px; --dy: -114px; animation-delay: 0s;" />
|
||||
<circle
|
||||
class="packet"
|
||||
cx="180"
|
||||
cy="150"
|
||||
r="3"
|
||||
style="--dx: 120px; --dy: -58px; animation-delay: -1.3s;" />
|
||||
<circle
|
||||
class="packet"
|
||||
cx="180"
|
||||
cy="150"
|
||||
r="3"
|
||||
style="--dx: -120px; --dy: -58px; animation-delay: -2.7s;" />
|
||||
<circle
|
||||
class="packet"
|
||||
cx="180"
|
||||
cy="150"
|
||||
r="3"
|
||||
style="--dx: 120px; --dy: 60px; animation-delay: -5.3s;" />
|
||||
<circle
|
||||
class="packet"
|
||||
cx="180"
|
||||
cy="150"
|
||||
r="3"
|
||||
style="--dx: -120px; --dy: 60px; animation-delay: -4s;" />
|
||||
<circle
|
||||
class="packet"
|
||||
cx="180"
|
||||
cy="150"
|
||||
r="3"
|
||||
style="--dx: 0px; --dy: 116px; animation-delay: -6.7s;" />
|
||||
</g>
|
||||
<g class="hub-dot">
|
||||
<circle cx="180" cy="36" r="9" />
|
||||
<circle cx="300" cy="92" r="9" />
|
||||
<circle cx="60" cy="92" r="9" />
|
||||
<circle cx="300" cy="210" r="9" />
|
||||
<circle cx="60" cy="210" r="9" />
|
||||
<circle cx="180" cy="266" r="9" />
|
||||
</g>
|
||||
<rect class="hub-chip" x="116" y="124" width="128" height="52" rx="10" />
|
||||
<text class="hub-title" x="180" y="147" text-anchor="middle">
|
||||
Central forge
|
||||
</text>
|
||||
<text class="hub-sub" x="180" y="166" text-anchor="middle">
|
||||
GitHub · GitLab
|
||||
</text>
|
||||
</svg>
|
||||
{:else if id === "nodes"}
|
||||
<svg class="diagram" viewBox="0 0 360 340" fill="none" aria-hidden="true">
|
||||
<g class="mesh-line">
|
||||
<line x1="180" y1="55" x2="274" y2="100" />
|
||||
<line x1="274" y1="100" x2="297" y2="202" />
|
||||
<line x1="297" y1="202" x2="232" y2="283" />
|
||||
<line x1="232" y1="283" x2="128" y2="283" />
|
||||
<line x1="128" y1="283" x2="63" y2="202" />
|
||||
<line x1="63" y1="202" x2="86" y2="100" />
|
||||
<line x1="86" y1="100" x2="180" y2="55" />
|
||||
<line x1="180" y1="55" x2="232" y2="283" />
|
||||
<line x1="274" y1="100" x2="128" y2="283" />
|
||||
<line x1="297" y1="202" x2="63" y2="202" />
|
||||
<line x1="180" y1="55" x2="297" y2="202" />
|
||||
<line x1="232" y1="283" x2="63" y2="202" />
|
||||
<line x1="128" y1="283" x2="86" y2="100" />
|
||||
</g>
|
||||
<g class="mesh-packets">
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="180"
|
||||
cy="55"
|
||||
r="3"
|
||||
style="--dx: 94px; --dy: 45px; --c: var(--color-accent-purple-500); animation-delay: 0s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="274"
|
||||
cy="100"
|
||||
r="3"
|
||||
style="--dx: 23px; --dy: 102px; --c: var(--color-accent-cyan-500); animation-delay: -0.6s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="297"
|
||||
cy="202"
|
||||
r="3"
|
||||
style="--dx: -65px; --dy: 81px; --c: var(--color-accent-citrus-500); animation-delay: -1.2s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="232"
|
||||
cy="283"
|
||||
r="3"
|
||||
style="--dx: -104px; --dy: 0px; --c: var(--color-accent-pink-500); animation-delay: -1.8s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="128"
|
||||
cy="283"
|
||||
r="3"
|
||||
style="--dx: -65px; --dy: -81px; --c: var(--color-accent-emerald-500); animation-delay: -2.5s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="63"
|
||||
cy="202"
|
||||
r="3"
|
||||
style="--dx: 23px; --dy: -102px; --c: var(--color-accent-olive-500); animation-delay: -3.1s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="86"
|
||||
cy="100"
|
||||
r="3"
|
||||
style="--dx: 94px; --dy: -45px; --c: var(--color-accent-purple-500); animation-delay: -3.7s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="180"
|
||||
cy="55"
|
||||
r="3"
|
||||
style="--dx: 52px; --dy: 228px; --c: var(--color-accent-cyan-500); animation-delay: -4.3s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="274"
|
||||
cy="100"
|
||||
r="3"
|
||||
style="--dx: -146px; --dy: 183px; --c: var(--color-accent-citrus-500); animation-delay: -4.9s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="297"
|
||||
cy="202"
|
||||
r="3"
|
||||
style="--dx: -234px; --dy: 0px; --c: var(--color-accent-pink-500); animation-delay: -5.5s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="180"
|
||||
cy="55"
|
||||
r="3"
|
||||
style="--dx: 117px; --dy: 147px; --c: var(--color-accent-emerald-500); animation-delay: -6.2s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="232"
|
||||
cy="283"
|
||||
r="3"
|
||||
style="--dx: -169px; --dy: -81px; --c: var(--color-accent-olive-500); animation-delay: -6.8s;" />
|
||||
<circle
|
||||
class="packet mesh-packet"
|
||||
cx="128"
|
||||
cy="283"
|
||||
r="3"
|
||||
style="--dx: -42px; --dy: -183px; --c: var(--color-accent-purple-500); animation-delay: -7.4s;" />
|
||||
</g>
|
||||
<rect
|
||||
class="nd-blue"
|
||||
x="160"
|
||||
y="35"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-green"
|
||||
x="254"
|
||||
y="80"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-purple"
|
||||
x="277"
|
||||
y="182"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-blue"
|
||||
x="212"
|
||||
y="263"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-green"
|
||||
x="108"
|
||||
y="263"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-purple"
|
||||
x="43"
|
||||
y="182"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<rect
|
||||
class="nd-blue"
|
||||
x="66"
|
||||
y="80"
|
||||
width="40"
|
||||
height="40"
|
||||
rx="12"
|
||||
fill-opacity="0.13" />
|
||||
<circle class="nd-blue" cx="180" cy="55" r="9" />
|
||||
<circle class="nd-green" cx="274" cy="100" r="9" />
|
||||
<circle class="nd-purple" cx="297" cy="202" r="9" />
|
||||
<circle class="nd-blue" cx="232" cy="283" r="9" />
|
||||
<circle class="nd-green" cx="128" cy="283" r="9" />
|
||||
<circle class="nd-purple" cx="63" cy="202" r="9" />
|
||||
<circle class="nd-blue" cx="86" cy="100" r="9" />
|
||||
</svg>
|
||||
{:else if id === "identity"}
|
||||
<span class="id-key" class:generating aria-hidden="true">
|
||||
<Icon name="key" />
|
||||
</span>
|
||||
<div class="did-key mono">
|
||||
<span class="did-prefix">did:key:</span>
|
||||
<span class="did-value">{didValue}</span>
|
||||
</div>
|
||||
{:else if id === "networking"}
|
||||
<svg class="diagram" viewBox="0 0 360 360" fill="none" aria-hidden="true">
|
||||
<g class="mesh-line">
|
||||
<line x1="239" y1="73" x2="298" y2="175" />
|
||||
<line x1="298" y1="175" x2="239" y2="277" />
|
||||
<line x1="239" y1="277" x2="121" y2="277" />
|
||||
<line x1="121" y1="277" x2="62" y2="175" />
|
||||
<line x1="62" y1="175" x2="121" y2="73" />
|
||||
<line x1="121" y1="73" x2="239" y2="73" />
|
||||
<line x1="239" y1="73" x2="239" y2="277" />
|
||||
<line x1="298" y1="175" x2="121" y2="277" />
|
||||
<line x1="298" y1="175" x2="121" y2="73" />
|
||||
<line x1="239" y1="277" x2="62" y2="175" />
|
||||
<line x1="121" y1="277" x2="121" y2="73" />
|
||||
<line x1="62" y1="175" x2="239" y2="73" />
|
||||
</g>
|
||||
<circle
|
||||
class="gossip-ripple"
|
||||
cx="180"
|
||||
cy="175"
|
||||
r="14"
|
||||
style="animation-delay: 0s;" />
|
||||
<circle
|
||||
class="gossip-ripple"
|
||||
cx="180"
|
||||
cy="175"
|
||||
r="14"
|
||||
style="animation-delay: -1s;" />
|
||||
<circle
|
||||
class="gossip-ripple"
|
||||
cx="180"
|
||||
cy="175"
|
||||
r="14"
|
||||
style="animation-delay: -2s;" />
|
||||
<circle class="nd-neutral" cx="239" cy="73" r="10" />
|
||||
<circle class="nd-neutral" cx="298" cy="175" r="10" />
|
||||
<circle class="nd-neutral" cx="239" cy="277" r="10" />
|
||||
<circle class="nd-neutral" cx="121" cy="277" r="10" />
|
||||
<circle class="nd-neutral" cx="62" cy="175" r="10" />
|
||||
<circle class="nd-neutral" cx="121" cy="73" r="10" />
|
||||
<circle class="nd-blue" cx="180" cy="175" r="22" fill-opacity="0.15" />
|
||||
<circle class="nd-blue" cx="180" cy="175" r="11" />
|
||||
</svg>
|
||||
{:else if id === "trust"}
|
||||
<div class="trust-figure">
|
||||
<div class="ref-card mono">
|
||||
<div class="ref-head">refs/rad/sigrefs</div>
|
||||
<div class="ref-row">
|
||||
<span class="hash">9767b485c2aad1e2</span>
|
||||
<span class="ref-path">refs/heads/master</span>
|
||||
</div>
|
||||
<div class="ref-row">
|
||||
<span class="hash">f3eaa7454e3a4714</span>
|
||||
<span class="ref-path">refs/cobs/xyz.radicle.patch/…</span>
|
||||
</div>
|
||||
<div class="ref-row">
|
||||
<span class="hash">0590b78ee42b3908</span>
|
||||
<span class="ref-path">refs/cobs/xyz.radicle.issue/…</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="signed-badge">
|
||||
<span class="signed-label txt-bold-16">Signed</span>
|
||||
<span class="signed-check">
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{:else if id === "collaboration"}
|
||||
<div class="repo-card">
|
||||
<div class="repo-head mono">rad:z3gqcJUoA1n9…</div>
|
||||
<div class="repo-rows">
|
||||
<div class="repo-row">
|
||||
<span class="dot dot-green"></span>
|
||||
<strong>Code</strong>
|
||||
<span class="repo-meta mono">commits & branches</span>
|
||||
</div>
|
||||
<div class="repo-row">
|
||||
<span class="dot dot-amber"></span>
|
||||
<strong>Issues</strong>
|
||||
<span class="repo-meta mono">xyz.radicle.issue</span>
|
||||
</div>
|
||||
<div class="repo-row">
|
||||
<span class="dot dot-purple"></span>
|
||||
<strong>Patches</strong>
|
||||
<span class="repo-meta mono">xyz.radicle.patch</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user