+72
-4
src/templates.rs
+72
-4
src/templates.rs
···
878
.onboarding-progress span.done {{
879
background: var(--text-light);
880
}}
881
</style>
882
</head>
883
<body>
···
886
887
<div class="overlay" id="overlay"></div>
888
<div class="info-modal" id="infoModal">
889
-
<h2>@me - your at protocol identity</h2>
890
-
<p>in decentralized social networks, you own your identity and your data lives in your personal data server (pds).</p>
891
-
<p>third-party applications create records in your repository using different lexicons (data schemas). for example, bluesky creates posts, white wind stores blog entries, tangled.org hosts code repositories, and frontpage aggregates links - all in the same place.</p>
892
-
<p>this visualization shows your identity at the center, surrounded by the third-party apps that have created data for you. click an app to see what types of records it stores, then click a record type to see the actual data.</p>
893
<button id="closeInfo">got it</button>
894
<button id="restartTour" onclick="window.restartOnboarding()" style="margin-left: 0.5rem; background: var(--surface-hover);">restart tour</button>
895
</div>
···
878
.onboarding-progress span.done {{
879
background: var(--text-light);
880
}}
881
+
882
+
.stats-box {{
883
+
display: flex;
884
+
gap: 1.5rem;
885
+
margin: 1.5rem 0;
886
+
padding: 1rem;
887
+
background: var(--bg);
888
+
border-radius: 4px;
889
+
border: 1px solid var(--border);
890
+
}}
891
+
892
+
.stat {{
893
+
flex: 1;
894
+
text-align: center;
895
+
}}
896
+
897
+
.stat-value {{
898
+
font-size: 1.8rem;
899
+
font-weight: 600;
900
+
color: var(--text);
901
+
margin-bottom: 0.25rem;
902
+
}}
903
+
904
+
.stat-label {{
905
+
font-size: 0.65rem;
906
+
color: var(--text-light);
907
+
text-transform: uppercase;
908
+
letter-spacing: 0.05em;
909
+
}}
910
+
911
+
.ownership-box {{
912
+
margin: 1rem 0;
913
+
padding: 1rem;
914
+
background: var(--bg);
915
+
border-radius: 4px;
916
+
border: 1px solid var(--border);
917
+
}}
918
+
919
+
.ownership-box.yours {{
920
+
background: rgba(76, 175, 80, 0.05);
921
+
border-color: rgba(76, 175, 80, 0.3);
922
+
}}
923
+
924
+
@media (prefers-color-scheme: dark) {{
925
+
.ownership-box.yours {{
926
+
background: rgba(76, 175, 80, 0.08);
927
+
border-color: rgba(76, 175, 80, 0.4);
928
+
}}
929
+
}}
930
+
931
+
.ownership-header {{
932
+
font-size: 0.7rem;
933
+
font-weight: 600;
934
+
color: var(--text);
935
+
margin-bottom: 0.5rem;
936
+
text-transform: uppercase;
937
+
letter-spacing: 0.05em;
938
+
}}
939
+
940
+
.ownership-text {{
941
+
font-size: 0.7rem;
942
+
color: var(--text-lighter);
943
+
line-height: 1.5;
944
+
}}
945
+
946
+
.ownership-text strong {{
947
+
color: var(--text);
948
+
}}
949
</style>
950
</head>
951
<body>
···
954
955
<div class="overlay" id="overlay"></div>
956
<div class="info-modal" id="infoModal">
957
+
<h2>@me - your repository</h2>
958
+
<p>on instagram, facebook, or twitter: the platform owns your content. if they ban you, it's all gone. you can't move it, export it, or control who accesses it.</p>
959
+
<p>on atproto: you own everything. your data lives in your personal server. apps like bluesky, whitewind, and frontpage just write to YOUR repository. you can switch apps, move servers, or revoke access anytime.</p>
960
+
<p>click your @ in the center to see what you've built. click any app to see what it's stored in your space.</p>
961
<button id="closeInfo">got it</button>
962
<button id="restartTour" onclick="window.restartOnboarding()" style="margin-left: 0.5rem; background: var(--surface-hover);">restart tour</button>
963
</div>
+42
-18
static/app.js
+42
-18
static/app.js
···
93
// User may not have an avatar set
94
});
95
96
// Add identity click handler to show PDS info
97
document.querySelector('.identity').addEventListener('click', () => {
98
const detail = document.getElementById('detail');
99
const pdsHost = pds.replace('https://', '').replace('http://', '');
100
detail.innerHTML = `
101
<button class="detail-close" id="detailClose">×</button>
102
-
<h3>your identity</h3>
103
-
<div class="subtitle">decentralized identifier & storage</div>
104
-
<div class="tree-item">
105
-
<div class="tree-item-header">
106
-
<span style="color: var(--text-light);">did</span>
107
-
<span style="font-size: 0.6rem; color: var(--text);">${did}</span>
108
</div>
109
-
</div>
110
-
<div class="tree-item">
111
-
<div class="tree-item-header">
112
-
<span style="color: var(--text-light);">handle</span>
113
-
<span style="font-size: 0.6rem; color: var(--text);">@${handle}</span>
114
</div>
115
</div>
116
-
<div class="tree-item">
117
-
<div class="tree-item-header">
118
-
<span style="color: var(--text-light);">personal data server</span>
119
-
<span style="font-size: 0.6rem; color: var(--text);">${pds}</span>
120
-
</div>
121
</div>
122
-
<div style="margin-top: 1rem; padding: 0.6rem; background: var(--bg); border-radius: 4px; font-size: 0.65rem; line-height: 1.5; color: var(--text-lighter);">
123
-
your data lives at <strong style="color: var(--text);">${pdsHost}</strong>. apps like bluesky write to and read from this server. you control @<strong style="color: var(--text);">${handle}</strong> and can move it to a different server anytime.
124
</div>
125
`;
126
detail.classList.add('visible');
···
138
.then(r => r.json())
139
.then(repo => {
140
const collections = repo.collections || [];
141
142
// Group by app namespace (first two parts of lexicon)
143
const apps = {};
···
93
// User may not have an avatar set
94
});
95
96
+
// Store collections for later use
97
+
let allCollections = [];
98
+
99
// Add identity click handler to show PDS info
100
document.querySelector('.identity').addEventListener('click', () => {
101
const detail = document.getElementById('detail');
102
const pdsHost = pds.replace('https://', '').replace('http://', '');
103
+
104
+
// Count total apps
105
+
const appCount = Object.keys(apps).length;
106
+
107
detail.innerHTML = `
108
<button class="detail-close" id="detailClose">×</button>
109
+
<h3>your repository</h3>
110
+
<div class="subtitle">what you've built</div>
111
+
112
+
<div class="stats-box">
113
+
<div class="stat">
114
+
<div class="stat-value">${allCollections.length}</div>
115
+
<div class="stat-label">record types</div>
116
</div>
117
+
<div class="stat">
118
+
<div class="stat-value">${appCount}</div>
119
+
<div class="stat-label">apps</div>
120
</div>
121
</div>
122
+
123
+
<div class="ownership-box">
124
+
<div class="ownership-header">on walled gardens</div>
125
+
<div class="ownership-text">platform owns your content. account ban = everything gone. no export, no control.</div>
126
</div>
127
+
128
+
<div class="ownership-box yours">
129
+
<div class="ownership-header">on atproto</div>
130
+
<div class="ownership-text">you own it. lives at <strong>${pdsHost}</strong>. move servers, switch apps, export anytime. can't be taken away.</div>
131
+
</div>
132
+
133
+
<div style="margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border);">
134
+
<div style="font-size: 0.65rem; color: var(--text-light); margin-bottom: 0.5rem;">technical details</div>
135
+
<div class="tree-item">
136
+
<div class="tree-item-header">
137
+
<span style="color: var(--text-light);">did</span>
138
+
<span style="font-size: 0.55rem; color: var(--text);">${did}</span>
139
+
</div>
140
+
</div>
141
+
<div class="tree-item">
142
+
<div class="tree-item-header">
143
+
<span style="color: var(--text-light);">handle</span>
144
+
<span style="font-size: 0.6rem; color: var(--text);">@${handle}</span>
145
+
</div>
146
+
</div>
147
</div>
148
`;
149
detail.classList.add('visible');
···
161
.then(r => r.json())
162
.then(repo => {
163
const collections = repo.collections || [];
164
+
allCollections = collections;
165
166
// Group by app namespace (first two parts of lexicon)
167
const apps = {};