tfrere HF Staff commited on
Commit
a90f930
·
1 Parent(s): 0b03a34

update thumb, perfs and remove pdf gate

Browse files
app/scripts/notion-importer/static/frontmatter.mdx CHANGED
@@ -49,7 +49,7 @@ tags:
49
  - data visualization
50
  tableOfContentsAutoCollapse: true
51
  seoThumbImage: "/thumb.png"
52
- pdfProOnly: true
53
  ---
54
 
55
 
 
49
  - data visualization
50
  tableOfContentsAutoCollapse: true
51
  seoThumbImage: "/thumb.png"
52
+ pdfProOnly: false
53
  ---
54
 
55
 
app/src/components/Hero.astro CHANGED
@@ -233,7 +233,7 @@ const pdfFilename = `${slugify(pdfBase)}.pdf`;
233
  // PDF access control for Pro users only
234
 
235
  // ⚙️ Configuration for local development
236
- const LOCAL_IS_PRO = false; // Set to true to test Pro access locally
237
 
238
  const FALLBACK_TIMEOUT_MS = 3000;
239
  let userPlanChecked = false;
 
233
  // PDF access control for Pro users only
234
 
235
  // ⚙️ Configuration for local development
236
+ const LOCAL_IS_PRO = true; // Set to true to test Pro access locally
237
 
238
  const FALLBACK_TIMEOUT_MS = 3000;
239
  let userPlanChecked = false;
app/src/components/HtmlEmbed.astro CHANGED
@@ -104,10 +104,18 @@ const htmlWithId =
104
 
105
  <script>
106
  // Re-execute <script> tags inside the injected fragment (innerHTML doesn't run scripts)
 
107
  const scriptEl = document.currentScript;
 
108
  const mount = scriptEl ? scriptEl.previousElementSibling : null;
 
 
 
 
109
  const execute = () => {
110
- if (!mount) return;
 
 
111
  const scripts = mount.querySelectorAll("script");
112
  scripts.forEach((old) => {
113
  // ignore non-executable types (e.g., application/json)
@@ -135,11 +143,66 @@ const htmlWithId =
135
  }
136
  }
137
  });
 
 
 
138
  };
139
- // Execute after DOM is parsed (ensures deferred module scripts are executed first)
140
- if (document.readyState === "loading")
141
- document.addEventListener("DOMContentLoaded", execute, { once: true });
142
- else execute();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  </script>
144
 
145
  <style is:global>
@@ -403,5 +466,35 @@ const htmlWithId =
403
  margin-left: auto !important;
404
  margin-right: auto !important;
405
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  }
407
  </style>
 
104
 
105
  <script>
106
  // Re-execute <script> tags inside the injected fragment (innerHTML doesn't run scripts)
107
+ // Uses IntersectionObserver for lazy loading - only executes when embed is visible
108
  const scriptEl = document.currentScript;
109
+ const figure = scriptEl?.previousElementSibling?.closest(".html-embed");
110
  const mount = scriptEl ? scriptEl.previousElementSibling : null;
111
+
112
+ if (!mount || !figure) return;
113
+
114
+ let executed = false;
115
  const execute = () => {
116
+ if (executed || !mount) return;
117
+ executed = true;
118
+
119
  const scripts = mount.querySelectorAll("script");
120
  scripts.forEach((old) => {
121
  // ignore non-executable types (e.g., application/json)
 
143
  }
144
  }
145
  });
146
+
147
+ // Mark as loaded
148
+ figure.classList.add("html-embed--loaded");
149
  };
150
+
151
+ // Check if IntersectionObserver is supported
152
+ if ("IntersectionObserver" in window) {
153
+ const observer = new IntersectionObserver(
154
+ (entries) => {
155
+ entries.forEach((entry) => {
156
+ if (entry.isIntersecting && !executed) {
157
+ observer.disconnect();
158
+ // Small delay to ensure DOM is ready
159
+ if (document.readyState === "loading") {
160
+ document.addEventListener("DOMContentLoaded", execute, {
161
+ once: true,
162
+ });
163
+ } else {
164
+ // Use requestAnimationFrame to ensure execution after DOM is fully ready
165
+ requestAnimationFrame(() => {
166
+ setTimeout(execute, 0);
167
+ });
168
+ }
169
+ }
170
+ });
171
+ },
172
+ {
173
+ // Start loading when element is 100px away from viewport
174
+ rootMargin: "100px",
175
+ threshold: 0.01,
176
+ },
177
+ );
178
+
179
+ observer.observe(figure);
180
+
181
+ // Fallback: if still not loaded after 3 seconds, load anyway (for edge cases)
182
+ setTimeout(() => {
183
+ if (!executed) {
184
+ observer.disconnect();
185
+ if (document.readyState === "loading") {
186
+ document.addEventListener("DOMContentLoaded", execute, {
187
+ once: true,
188
+ });
189
+ } else {
190
+ requestAnimationFrame(() => {
191
+ setTimeout(execute, 0);
192
+ });
193
+ }
194
+ }
195
+ }, 3000);
196
+ } else {
197
+ // Fallback for browsers without IntersectionObserver support
198
+ if (document.readyState === "loading") {
199
+ document.addEventListener("DOMContentLoaded", execute, { once: true });
200
+ } else {
201
+ requestAnimationFrame(() => {
202
+ setTimeout(execute, 0);
203
+ });
204
+ }
205
+ }
206
  </script>
207
 
208
  <style is:global>
 
466
  margin-left: auto !important;
467
  margin-right: auto !important;
468
  }
469
+ /* Better rendering for d3-loss-curves when printing */
470
+ .html-embed .d3-loss-curves {
471
+ width: 100% !important;
472
+ height: auto !important;
473
+ min-height: 300px !important;
474
+ margin-left: auto !important;
475
+ margin-right: auto !important;
476
+ overflow: visible !important;
477
+ }
478
+ .html-embed .d3-loss-curves svg {
479
+ width: 100% !important;
480
+ height: auto !important;
481
+ max-height: 500px !important;
482
+ }
483
+ /* Ensure legend is visible in print */
484
+ .html-embed .d3-loss-curves .legend {
485
+ position: relative !important;
486
+ display: flex !important;
487
+ flex-direction: column !important;
488
+ align-items: flex-start !important;
489
+ gap: 4px !important;
490
+ margin-top: 10px !important;
491
+ bottom: auto !important;
492
+ left: auto !important;
493
+ max-width: 100% !important;
494
+ }
495
+ /* Hide annotation in print */
496
+ .html-embed .d3-loss-curves .annotation {
497
+ display: none !important;
498
+ }
499
  }
500
  </style>