atproto-embed 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/embed.js ADDED
@@ -0,0 +1,197 @@
1
+ (function () {
2
+ "use strict";
3
+
4
+ var RUNTIME_CONFIG = {
5
+ post: {
6
+ selector: ".atproto-embed:not([data-embed-child])",
7
+ file: "post.js",
8
+ api: "AtProtoEmbed",
9
+ },
10
+ profile: {
11
+ selector: ".atproto-profile:not([data-profile-child])",
12
+ file: "profile.js",
13
+ api: "AtProtoProfile",
14
+ },
15
+ members: {
16
+ selector: ".atproto-members:not([data-members-child])",
17
+ file: "members.js",
18
+ api: "AtProtoMembers",
19
+ },
20
+ };
21
+
22
+ var RUNTIME_LOADS = {};
23
+
24
+ function resolveLoaderSrc() {
25
+ var current = document.currentScript;
26
+ if (current && current.src) return current.src;
27
+
28
+ var scripts = document.querySelectorAll("script[src]");
29
+ for (var i = scripts.length - 1; i >= 0; i--) {
30
+ var src = scripts[i].src || scripts[i].getAttribute("src") || "";
31
+ if (src.indexOf("embed.js") !== -1) return src;
32
+ }
33
+ return "";
34
+ }
35
+
36
+ function splitSrc(src) {
37
+ if (!src) return { base: "./", query: "" };
38
+ try {
39
+ var u = new URL(src, window.location.href);
40
+ var path = u.pathname || "/";
41
+ var slash = path.lastIndexOf("/");
42
+ var basePath = slash >= 0 ? path.slice(0, slash + 1) : "/";
43
+ return {
44
+ base: (u.origin && u.origin !== "null" ? u.origin : u.protocol + "//") + basePath,
45
+ query: u.search || "",
46
+ };
47
+ } catch (_) {
48
+ var clean = src.split("#")[0];
49
+ var q = "";
50
+ var qIdx = clean.indexOf("?");
51
+ if (qIdx !== -1) {
52
+ q = clean.slice(qIdx);
53
+ clean = clean.slice(0, qIdx);
54
+ }
55
+ var idx = clean.lastIndexOf("/");
56
+ return {
57
+ base: idx >= 0 ? clean.slice(0, idx + 1) : "./",
58
+ query: q,
59
+ };
60
+ }
61
+ }
62
+
63
+ var LOADER_PARTS = splitSrc(resolveLoaderSrc());
64
+
65
+ function runtimeUrl(fileName) {
66
+ return LOADER_PARTS.base + fileName + LOADER_PARTS.query;
67
+ }
68
+
69
+ function getRuntimeApi(apiName) {
70
+ if (typeof window === "undefined") return null;
71
+ return window[apiName] || null;
72
+ }
73
+
74
+ function scriptMatches(script, key, url, fileName) {
75
+ if (!script) return false;
76
+ if (script.getAttribute("data-atproto-runtime") === key) return true;
77
+ var src = script.getAttribute("src") || script.src || "";
78
+ if (!src) return false;
79
+ try {
80
+ var sourceUrl = new URL(src, window.location.href);
81
+ var targetUrl = new URL(url, window.location.href);
82
+ return sourceUrl.href === targetUrl.href || sourceUrl.pathname === targetUrl.pathname;
83
+ } catch (_) {
84
+ return src === url || src.indexOf(fileName) !== -1;
85
+ }
86
+ }
87
+
88
+ function ensureRuntimeLoaded(key) {
89
+ var cfg = RUNTIME_CONFIG[key];
90
+ if (!cfg) return Promise.resolve(null);
91
+
92
+ var loadedApi = getRuntimeApi(cfg.api);
93
+ if (loadedApi) return Promise.resolve(loadedApi);
94
+
95
+ if (RUNTIME_LOADS[key]) return RUNTIME_LOADS[key];
96
+
97
+ var url = runtimeUrl(cfg.file);
98
+ var script = null;
99
+ var scripts = document.querySelectorAll("script[src]");
100
+ for (var i = 0; i < scripts.length; i++) {
101
+ if (scriptMatches(scripts[i], key, url, cfg.file)) {
102
+ script = scripts[i];
103
+ break;
104
+ }
105
+ }
106
+
107
+ var p = new Promise(function (resolve, reject) {
108
+ function onLoad() {
109
+ cleanup();
110
+ resolve(getRuntimeApi(cfg.api));
111
+ }
112
+
113
+ function onError() {
114
+ cleanup();
115
+ reject(new Error("Failed to load runtime: " + cfg.file));
116
+ }
117
+
118
+ function cleanup() {
119
+ script.removeEventListener("load", onLoad);
120
+ script.removeEventListener("error", onError);
121
+ }
122
+
123
+ if (!script) {
124
+ script = document.createElement("script");
125
+ script.src = url;
126
+ script.async = true;
127
+ script.setAttribute("data-atproto-runtime", key);
128
+ document.head.appendChild(script);
129
+ }
130
+
131
+ var existingApi = getRuntimeApi(cfg.api);
132
+ if (existingApi) {
133
+ resolve(existingApi);
134
+ return;
135
+ }
136
+
137
+ script.addEventListener("load", onLoad);
138
+ script.addEventListener("error", onError);
139
+ })
140
+ .finally(function () {
141
+ delete RUNTIME_LOADS[key];
142
+ });
143
+
144
+ RUNTIME_LOADS[key] = p;
145
+ return p;
146
+ }
147
+
148
+ function callRuntimeInit(api) {
149
+ if (!api) return;
150
+ if (typeof api.init === "function") {
151
+ api.init(false);
152
+ return;
153
+ }
154
+ if (typeof api.refresh === "function") {
155
+ api.refresh();
156
+ }
157
+ }
158
+
159
+ function collectRequiredRuntimes() {
160
+ var keys = [];
161
+ for (var key in RUNTIME_CONFIG) {
162
+ if (!Object.prototype.hasOwnProperty.call(RUNTIME_CONFIG, key)) continue;
163
+ var cfg = RUNTIME_CONFIG[key];
164
+ if (document.querySelector(cfg.selector)) keys.push(key);
165
+ }
166
+ return keys;
167
+ }
168
+
169
+ function init() {
170
+ var keys = collectRequiredRuntimes();
171
+ if (!keys.length) return Promise.resolve();
172
+
173
+ return Promise.all(
174
+ keys.map(function (key) {
175
+ return ensureRuntimeLoaded(key).then(function (api) {
176
+ callRuntimeInit(api);
177
+ return api;
178
+ });
179
+ })
180
+ ).catch(function (err) {
181
+ console.error("[atproto-loader]", err);
182
+ });
183
+ }
184
+
185
+ if (document.readyState === "loading") {
186
+ document.addEventListener("DOMContentLoaded", init);
187
+ } else {
188
+ init();
189
+ }
190
+
191
+ if (typeof window !== "undefined") {
192
+ window.AtProtoLoader = window.AtProtoLoader || {};
193
+ window.AtProtoLoader.refresh = function () {
194
+ return init();
195
+ };
196
+ }
197
+ })();
@@ -0,0 +1,248 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Google+Sans+Flex:opsz,wght@6..144,1..1000&display=swap');
2
+
3
+ :host {
4
+ /* Neutral palette */
5
+ --neutral-0: #ffffff;
6
+ --neutral-1: #f8f9fa;
7
+ --neutral-2: #f1f3f5;
8
+ --neutral-3: #e9ecef;
9
+ --neutral-4: #dee2e6;
10
+ --neutral-5: #ced4da;
11
+ --neutral-6: #adb5bd;
12
+ --neutral-7: #6a7178;
13
+ --neutral-8: #4f575e;
14
+ --neutral-9: #272b30;
15
+ --neutral-10: #101213;
16
+ --neutral-11: #000000;
17
+
18
+ /* Primary */
19
+ --primary-light: #f8f9ff;
20
+ --primary-base: #0a66f4;
21
+ --primary-hover: #20439b;
22
+ --primary-dark: #1c2855;
23
+
24
+ /* Type scale */
25
+ --font-displayLarge: 45px;
26
+ --font-displaymedium: 40px;
27
+ --font-displaySmall: 36px;
28
+ --font-heading1: 32px;
29
+ --font-heading2: 28px;
30
+ --font-heading3: 25px;
31
+ --font-heading4: 22px;
32
+ --font-heading5: 20px;
33
+ --font-heading6: 18px;
34
+ --font-subtitle: 16px;
35
+ --font-body: 14px;
36
+ --font-caption: 12px;
37
+ --font-label: 11px;
38
+ --font-tagline: 10px;
39
+ --font-sans: "Google Sans Flex", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
40
+ --transition: all 0.32s ease-in-out;
41
+
42
+ /* Inherit shared variables from root or use standard defaults */
43
+ --atproto-columns: 3;
44
+ --atproto-bg: var(--neutral-0, #ffffff);
45
+ --atproto-border-color: var(--neutral-3, #e9ecef);
46
+ --atproto-text-color: var(--neutral-10, #101213);
47
+ --atproto-muted-color: var(--neutral-7, #6a7178);
48
+ --atproto-accent-color: var(--primary-base, #0a66f4);
49
+ --atproto-radius: 12px;
50
+ --atproto-font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);
51
+ }
52
+
53
+ :host(.atproto-members-host) {
54
+ display: block;
55
+ width: var(--atproto-width, 100%);
56
+ max-width: var(--atproto-max-width, none);
57
+ margin: 32px auto;
58
+ font-family: var(--atproto-font-family);
59
+ color: var(--atproto-text-color);
60
+ }
61
+
62
+ .atproto-members-inner {
63
+ width: 100%;
64
+ }
65
+
66
+ .atproto-members--loading,
67
+ .atproto-members--error,
68
+ .atproto-members__empty {
69
+ padding: 18px;
70
+ border: 1px solid var(--atproto-border-color);
71
+ border-radius: var(--atproto-radius);
72
+ background: var(--atproto-bg);
73
+ color: var(--atproto-muted-color);
74
+ text-align: center;
75
+ font-size: var(--font-body, 14px);
76
+ }
77
+
78
+ .atproto-members__grid {
79
+ display: grid;
80
+ grid-template-columns: repeat(var(--atproto-columns, 3), minmax(0, 1fr));
81
+ gap: 8px;
82
+ }
83
+
84
+ .atproto-members__grid--avatar-only {
85
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr)) !important;
86
+ justify-items: center;
87
+ }
88
+
89
+ @media (max-width: 1024px) {
90
+ .atproto-members__grid {
91
+ grid-template-columns: repeat(var(--atproto-columns-md, var(--atproto-columns, 3)), minmax(0, 1fr));
92
+ }
93
+
94
+ .atproto-members__grid--avatar-only {
95
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
96
+ }
97
+ }
98
+
99
+ @media (max-width: 768px) {
100
+ .atproto-members__grid {
101
+ grid-template-columns: repeat(var(--atproto-columns-sm, var(--atproto-columns-md, var(--atproto-columns, 3))), minmax(0, 1fr));
102
+ }
103
+
104
+ .atproto-members__grid--avatar-only {
105
+ grid-template-columns: repeat(auto-fit, minmax(46px, 1fr));
106
+ }
107
+ }
108
+
109
+ .atproto-members__button-row {
110
+ display: flex;
111
+ justify-content: center;
112
+ margin-top: 24px;
113
+ }
114
+
115
+ .atproto-members__button {
116
+ display: inline-flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ padding: 8px 20px;
120
+ border-radius: 100px;
121
+ font-size: var(--font-body);
122
+ font-weight: 600;
123
+ text-decoration: none;
124
+ transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
125
+ }
126
+
127
+ .atproto-members__button--filled {
128
+ background: var(--primary-base);
129
+ color: #ffffff;
130
+ border: 1px solid var(--primary-base);
131
+ }
132
+
133
+ .atproto-members__button--filled:hover {
134
+ background: var(--primary-hover);
135
+ }
136
+
137
+ .atproto-members__button--outline {
138
+ background: transparent;
139
+ color: var(--neutral-11);
140
+ border: 2px solid var(--neutral-1);
141
+ }
142
+
143
+ .atproto-members__button--outline:hover {
144
+ background: var(--neutral-3);
145
+ border-color: var(--neutral-3);
146
+ }
147
+
148
+ .atproto-members__card {
149
+ display: flex;
150
+ gap: 10px;
151
+ padding: 12px;
152
+ background: var(--neutral-0);
153
+ border: 2px solid var(--neutral-1);
154
+ border-radius: 12px;
155
+ align-items: flex-start;
156
+ transition: var(--transition);
157
+ }
158
+
159
+ .atproto-members__card--avatar-only {
160
+ justify-content: center;
161
+ align-items: center;
162
+ padding: 4px;
163
+ border-radius: 50%;
164
+ width: 46px;
165
+ height: 46px;
166
+ gap: 0;
167
+ box-sizing: border-box;
168
+ }
169
+
170
+ .atproto-members__card--avatar-only .atproto-members__meta {
171
+ display: none;
172
+ }
173
+
174
+ .atproto-members__card-link {
175
+ display: block;
176
+ text-decoration: none;
177
+ color: inherit;
178
+ }
179
+
180
+ .atproto-members__card-link:hover .atproto-members__card {
181
+ border-color: var(--neutral-3);
182
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
183
+ transform: translateY(-1px);
184
+ }
185
+
186
+ .atproto-members__avatar {
187
+ width: 38px;
188
+ height: 38px;
189
+ border-radius: 50%;
190
+ object-fit: cover;
191
+ flex-shrink: 0;
192
+ }
193
+
194
+ .atproto-members__meta {
195
+ display: flex;
196
+ flex-direction: column;
197
+ gap: 4px;
198
+ min-width: 0;
199
+ }
200
+
201
+ .atproto-members__name-row {
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 4px;
205
+ }
206
+
207
+ .atproto-members__name {
208
+ font-size: var(--font-caption);
209
+ font-weight: 600;
210
+ color: var(--neutral-11);
211
+ overflow: hidden;
212
+ text-overflow: ellipsis;
213
+ white-space: nowrap;
214
+ }
215
+
216
+ .atproto-members__badge {
217
+ width: 14px;
218
+ height: 14px;
219
+ }
220
+
221
+ .atproto-members__handle {
222
+ font-size: var(--font-caption);
223
+ color: var(--neutral-8);
224
+ overflow: hidden;
225
+ text-overflow: ellipsis;
226
+ white-space: nowrap;
227
+ }
228
+
229
+ .atproto-members__metrics {
230
+ display: flex;
231
+ gap: 8px;
232
+ margin-top: 2px;
233
+ }
234
+
235
+ .atproto-members__metric {
236
+ display: flex;
237
+ align-items: center;
238
+ gap: 4px;
239
+ font-size: var(--font-tagline);
240
+ color: var(--neutral-7);
241
+ white-space: nowrap;
242
+ }
243
+
244
+ @media (max-width: 480px) {
245
+ .atproto-members__grid {
246
+ grid-template-columns: repeat(var(--atproto-columns-xs, var(--atproto-columns-sm, var(--atproto-columns, 3))), minmax(0, 1fr));
247
+ }
248
+ }