+3
-3
README.md
+3
-3
README.md
···
1
1
# @me
2
2
3
-
an accessible visualization of how your atproto identity connects to third-party apps.
3
+
an accessible visualization of how your atproto identity connects to atproto apps.
4
4
5
5
[at-me.fly.dev](https://at-me.fly.dev/)
6
6
7
7
## what is this
8
8
9
-
in decentralized social networks, you own your identity and your data lives in your personal data server. third-party applications create records in your repository using different lexicons (data schemas).
9
+
in decentralized social networks, you own your identity and your data lives in your personal data server. atproto applications create records in your repository using different lexicons (data schemas).
10
10
11
-
@me shows this visually: your identity at the center, surrounded by the third-party apps that have created data for you. click an app to see what record types it stores, then click a record type to view the actual data.
11
+
@me shows this visually: your identity at the center, surrounded by the atproto apps that have created data for you. click an app to see what record types it stores, then click a record type to view the actual data.
12
12
13
13
inspired by [pdsls.dev](https://pdsls.dev).
14
14
+2
-9
src/templates.rs
+2
-9
src/templates.rs
···
735
735
line-height: 1.2;
736
736
}}
737
737
738
-
.identity-hint {{
739
-
font-size: clamp(0.35rem, 0.8vmin, 0.45rem);
740
-
color: var(--text-lighter);
741
-
margin-top: clamp(0.4rem, 1.5vmin, 0.6rem);
742
-
letter-spacing: 0.05em;
743
-
}}
744
738
745
739
.identity-pds-label {{
746
740
position: absolute;
···
781
775
background: var(--surface-hover);
782
776
border: 1px solid var(--border);
783
777
border-radius: 50%;
784
-
width: clamp(45px, 8vmin, 60px);
785
-
height: clamp(45px, 8vmin, 60px);
778
+
width: clamp(55px, 10vmin, 70px);
779
+
height: clamp(55px, 10vmin, 70px);
786
780
display: flex;
787
781
align-items: center;
788
782
justify-content: center;
···
1636
1630
<div class="identity">
1637
1631
<div class="identity-label">@</div>
1638
1632
<div class="identity-value" id="handle">loading...</div>
1639
-
<div class="identity-hint">tap for details</div>
1640
1633
<div class="identity-pds-label">Your PDS</div>
1641
1634
</div>
1642
1635
<div id="field" class="loading">loading...</div>
+35
static/app.js
+35
static/app.js
···
4
4
5
5
let globalPds = null;
6
6
let globalHandle = null;
7
+
let globalApps = null; // Store apps for repositioning on resize
7
8
8
9
// Fetch app avatar from server
9
10
async function fetchAppAvatar(namespace) {
···
62
63
apps[app.namespace] = app.collections;
63
64
allCollections.push(...app.collections);
64
65
});
66
+
67
+
// Store apps globally for repositioning
68
+
globalApps = apps;
65
69
66
70
// Add identity click handler now that we have the data
67
71
const pdsHost = globalPds.replace('https://', '').replace('http://', '');
···
466
470
document.getElementById('detail').classList.remove('visible');
467
471
}
468
472
});
473
+
474
+
// Add window resize handler to reposition app circles
475
+
let resizeTimeout;
476
+
window.addEventListener('resize', () => {
477
+
clearTimeout(resizeTimeout);
478
+
resizeTimeout = setTimeout(() => {
479
+
repositionAppCircles();
480
+
}, 100); // Debounce resize events
481
+
});
469
482
})
470
483
.catch(e => {
471
484
document.getElementById('field').innerHTML = 'error loading records';
472
485
console.error(e);
473
486
});
487
+
488
+
// Function to reposition app circles on window resize
489
+
function repositionAppCircles() {
490
+
if (!globalApps) return;
491
+
492
+
const appViews = document.querySelectorAll('.app-view');
493
+
const appNames = Object.keys(globalApps).sort();
494
+
495
+
const vmin = Math.min(window.innerWidth, window.innerHeight);
496
+
const radius = Math.max(vmin * 0.35, 150);
497
+
const centerX = window.innerWidth / 2;
498
+
const centerY = window.innerHeight / 2;
499
+
500
+
appViews.forEach((div, i) => {
501
+
const angle = (i / appNames.length) * 2 * Math.PI - Math.PI / 2;
502
+
const x = centerX + radius * Math.cos(angle) - 30;
503
+
const y = centerY + radius * Math.sin(angle) - 30;
504
+
505
+
div.style.left = `${x}px`;
506
+
div.style.top = `${y}px`;
507
+
});
508
+
}
474
509
475
510
// MST Visualization Functions
476
511
async function loadMSTStructure(lexicon, containerView) {
+1
-1
static/onboarding.js
+1
-1
static/onboarding.js