PageSourceSearch

https://social-widget-hub-3ak0as88.taskade.app/

html social-widget-hub-3ak0as88.taskade.app collected 2026-10-03 15:05:26 UTC 26,988 bytes, 587 lines download raw bytes

1<!doctype html><html lang="en"><head><meta charset="UTF-8"><link rel="icon" type="image/png" href="/logo.png"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>Built with Taskade</title>
1<script defer src="./assets/main.a129f9.js"></script>
1<link href="./assets/main.9b68a1.css" rel="stylesheet"><meta charset="utf-8" /><meta name="language" content="en-US" /><meta name="robots" content="noindex,nofollow" /><meta name="author" content="Taskade" /><link rel="icon" sizes="32x32" href="/_genesis/assets/favicon" /><link rel="apple-touch-icon" sizes="180x180" href="/_genesis/assets/favicon" /><meta name="title" content="Built with Taskade" /><meta property="og:title" content="Built with Taskade" /><meta name="twitter:title" content="Built with Taskade" /><meta name="description" content="A living app built with Taskade Genesis. One prompt, one app. Projects remember, agents learn, and workflows move." /><meta property="og:description" content="A living app built with Taskade Genesis. One prompt, one app. Projects remember, agents learn, and workflows move." /><meta name="twitter:description" content="A living app built with Taskade Genesis. One prompt, one app. Projects remember, agents learn, and workflows move." /><meta property="og:type" content="website" /><meta property="og:url" content="https://social-widget-hub-3ak0as88.taskade.app" /><meta property="og:site_name" content="Taskade" /><meta property="og:image" content="https://social-widget-hub-3ak0as88.taskade.app/_internal/screenshot" /><meta property="og:image:alt" content="Built with Taskade - A living app built with Taskade Genesis. One prompt, one app. Projects remember, agents learn, and w..." /><meta property="og:locale" content="en_US" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:site" content="@taskade" /><meta name="twitter:creator" content="@taskade" /><meta name="twitter:image" content="https://social-widget-hub-3ak0as88.taskade.app/_internal/screenshot" /><meta name="twitter:image:alt" content="Built with Taskade - A living app built with Taskade Genesis. One prompt, one app. Projects remember, agents learn, and w..." /><meta name="format-detection" content="telephone=no" /><meta name="mobile-web-app-capable" content="yes" /><meta name="apple-mobile-web-app-capable" content="yes" /><meta name="apple-mobile-web-app-status-bar-style" content="default" /><meta name="apple-mobile-web-app-title" content="Built with Taskade" /><meta name="application-name" content="Taskade" /><link rel="canonical" href="https://social-widget-hub-3ak0as88.taskade.app" />
1<script type="application/ld+json">
2  {
3    "@context": "https://schema.org",
4    "@type": "WebSite",
5    "name": "Taskade",
6    "alternateName": "Built with Taskade",
7    "description": "A living app built with Taskade Genesis. One prompt, one app. Projects remember, agents learn, and workflows move.",
8    "image": "https://social-widget-hub-3ak0as88.taskade.app/_internal/screenshot",
9    "url": "https://social-widget-hub-3ak0as88.taskade.app",
10    "author": {
11      "@type": "Organization",
12      "name": "Taskade"
13    },
14    "publisher": {
15      "@type": "Organization",
16      "name": "Taskade",
17      "url": "https://social-widget-hub-3ak0as88.taskade.app",
18      "logo": {
19        "@type": "ImageObject",
20        "url": "https://social-widget-hub-3ak0as88.taskade.app/_internal/screenshot"
21      }
22    }
23  }
24</script>
24<script defer src="/_genesis/vendor/flock.min.js" data-proxy-url="/_genesis/api/events" data-tenant-id="hukxgm8wfgw2y2mq:default" data-domain="social-widget-hub-3ak0as88.taskade.app"></script>
24<script defer src="/_genesis/vendor/scroll-guard.js"></script>
24</head><body>
24<script>
25      (function() {
26        if (window.__genesisErrorCatchAll) return;
27        window.__genesisErrorCatchAll = true;
28        var esc = function(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); };
29        var errorHtml = function(msg, id) {
30          return '<div style="position:fixed;inset:0;background:#000;padding:2rem;font-family:system-ui,sans-serif;color:#fff;overflow:auto">' +
31            '<div style="max-width:600px;margin:0 auto">' +
32            '<h2 style="margin:0 0 0.5rem;font-size:1.25rem">Something went wrong</h2>' +
33            '<p style="color:#999;margin:0 0 1rem;font-size:0.95rem">The app failed to load. Try refreshing the page.</p>' +
34            '<pre style="background:#1a1a1a;padding:1rem;border-radius:8px;overflow:auto;font-size:0.8rem;color:#f87171;margin:0;white-space:pre-wrap;word-break:break-word">' +
35            esc(msg) + '<\/pre>' +
36            '<p style="color:#666;margin:1rem 0 0;font-size:0.75rem">Error ID: <code>' + esc(id) + '<\/code><\/p>' +
37            '<\/div><\/div>';
38        };
39        var reported = false;
40        var errorId = null;
41        function getErrorId() {
42          if (errorId != null) return errorId;
43          try {
44            if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { errorId = crypto.randomUUID().replace(/-/g, ''); return errorId; }
45          } catch (e) { /* Fall through to the time+random id below */ }
46          errorId = Date.now().toString(36) + Math.random().toString(36).slice(2, 12);
47          return errorId;
48        }
49        function reportError(code, msg, stack) {
50          if (reported) return;
51          reported = true;
52          try {
53            var logger = window.__TASKADE_APP_LIFECYCLE_LOGGER__;
54            if (typeof logger?.log === 'function') {
55              logger.log({ level: 'error', message: 'Runtime Error', data: { code: code, message: msg, stack: stack || '' } });
56              return;
57            }
58            // Published: no logger, so beacon to the Taskade gateway instead of
59            // dropping the crash on the floor (#27626). Relative path — the
60            // Director proxy injects the gateway token server-side. Once per page
61            // session (the latch above) so a crash loop cannot flood the sink.
62            fetch('/api/taskade/telemetry/errors', {
63              method: 'POST',
64              headers: { 'Content-Type': 'application/json' },
65              body: JSON.stringify({
66                errorId: getErrorId(),
67                code: code,
68                message: String(msg || 'Unknown error').slice(0, 4000),
69                stack: String(stack || '').slice(0, 20000),
70                path: location.pathname.slice(0, 1000),
71                userAgent: navigator.userAgent.slice(0, 512)
72              }),
73              keepalive: true
74              // Default same-origin credentials: a password-protected app gates
75              // /api/taskade/* on its signed access cookie, so omitting them
76              // would redirect the beacon to the password page.
77            }).catch(function() {});
78          } catch (e) { /* Swallow — never block the fallback error UI */ }
79        }
80        function showError(code, msg, stack) {
81          var root = document.getElementById('root');
82          if (!root) return;
83          var spinner = root.querySelector('.genesis__spinner-container');
84          if (spinner) {
85            // Scenario 1: React never mounted — replace spinner
86            reportError('error.fatal', msg, stack);
87            spinner.outerHTML = errorHtml(msg, getErrorId());
88          } else if (!root.childElementCount) {
89            // Scenario 2: React crashed and unmounted — #root is empty
90            reportError('error.fatal', msg, stack);
91            root.innerHTML = errorHtml(msg, getErrorId());
92          } else {
93            // React is running fine — don't interfere with the DOM,
94            // but still report with the original code for diagnostics
95            reportError(code, msg, stack);
96          }
97        }
98        window.addEventListener('error', function(e) {
99          var msg = e.message || String(e.error) || 'Unknown error';
100          var stack = e.error && e.error.stack ? e.error.stack : (e.filename ? e.filename + ':' + e.lineno + ':' + e.colno : '');
101          showError('error.runtime_error', msg, stack);
102        });
103        window.addEventListener('unhandledrejection', function(e) {
104          var msg = e.reason ? String(e.reason) : 'Unhandled promise rejection';
105          var stack = e.reason && e.reason.stack ? e.reason.stack : '';
106          showError('error.unhandled_promise', msg, stack);
107        });
108        // A dead <img> degrades to a neutral placeholder instead of painting its
109        // raw alt string across the page (#27730) — the symptom half of the
110        // fabricated-hot-link fix, and the only half that helps an ALREADY
111        // published app, whose images can rot long after generation.
112        //
113        // Resource load errors do not bubble, so they reach window only in the
114        // CAPTURE phase. That is why neither handler above has ever seen one, and
115        // why this cannot disturb them: a broken image must never render the fatal
116        // error overlay or spend the once-per-session crash beacon.
117        //
118        // Swapping in a 1x1 transparent GIF is what actually stops the alt text —
119        // the element becomes a SUCCESSFUL load, so the browser has no broken image
120        // to caption, while the alt attribute stays for assistive tech. Layout is
121        // untouched: the app's own width/height/aspect classes still apply. The grey
122        // is translucent so it reads correctly on a light or a dark surface without
123        // this script having to know the app's theme.
124        var deadImagePixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
125        window.addEventListener('error', function(e) {
126          var el = e.target;
127          if (!el || el.tagName !== 'IMG') return;
128          // The swap fires a fresh load on the same element, so the latch is what
129          // keeps a failing data URI from looping.
130          if (el.getAttribute('data-genesis-image-fallback') !== null) return;
131          el.setAttribute('data-genesis-image-fallback', '');
132          el.removeAttribute('srcset');
133          el.src = deadImagePixel;
134          el.style.background = 'linear-gradient(135deg, rgba(127,127,127,0.16), rgba(127,127,127,0.28))';
135        }, true);
136
137        // ---------------------------------------------------------------
138        // Dead env reads (advisory, NOT a failure)
139        // ---------------------------------------------------------------
140        // The bundle's import.meta.env / process.env shims are reporting
141        // Proxies (see genesisEnvBanner.ts). They are value-preserving: a
142        // missing key still reads undefined. This turns that read from invisible
143        // into observable, because a feature gated on one is permanently off and
144        // has no other symptom — the app builds, boots and looks healthy.
145        //
146        // Deliberately WARN, never error. The runtime cannot see whether a call
147        // site has a working fallback, so a correct
148        // VITE_API_BASE_URL || 'https://real' is reported too. Warn keeps it
149        // out of the "Fix with AI" popup set and out of FATAL_LIFECYCLE_CODES,
150        // both of which are error-level allowlists.
151        var deadEnvSeen = {};
152        var deadEnvSent = 0;
153        // Its OWN budget and latch: sharing the 'reported' latch above would let
154        // an advisory notice spend the one crash report this page session gets.
155        var DEAD_ENV_MAX = 5;
156        function reportDeadEnv(source, key) {
157          try {
158            var signature = source + '.' + key;
159            if (deadEnvSeen[signature] || deadEnvSent >= DEAD_ENV_MAX) return;
160            deadEnvSeen[signature] = 1;
161            deadEnvSent++;
162            var msg = signature + ' is read but a Genesis build never defines it, so the value is ' +
163              'always undefined. If it gates a feature, that feature is permanently off. Route ' +
164              'secret-bearing calls through GenesisClient.proxy() with a secretAlias instead.';
165            var logger = window.__TASKADE_APP_LIFECYCLE_LOGGER__;
166            if (typeof logger?.log === 'function') {
167              logger.log({ level: 'warn', message: 'Dead env read', data: { code: 'warn.dead_env', message: msg } });
168              return;
169            }
170            fetch('/api/taskade/telemetry/errors', {
171              method: 'POST',
172              headers: {
173                'Content-Type': 'application/json',
174                // Lets the publish Worker pick the advisory rate-limit bucket
175                // without reading this body. Doing that at the edge means I/O
176                // of unbounded duration ahead of the limiter meant to bound it,
177                // which is the whole class of problem the header avoids. The
178                // origin still classifies from the validated body, so this is a
179                // bucket hint and never the record (#29164).
180                'X-Genesis-Telemetry-Code': 'warn.dead_env'
181              },
182              body: JSON.stringify({
183                errorId: 'de' + Date.now().toString(36) + Math.random().toString(36).slice(2, 8),
184                code: 'warn.dead_env',
185                message: msg.slice(0, 4000),
186                path: location.pathname.slice(0, 1000),
187                // The source and key as STRUCTURE, not only inside the prose.
188                // The gateway fingerprints on app + code alone, because this
189                // endpoint's token ships in the bundle and free text from it
190                // cannot be trusted; these two validated fields are how the
191                // key still reaches Sentry, as a tag.
192                // Sliced to the schema's bound like every other field here: the
193                // banner filters the key's SHAPE but not its length, and an
194                // over-long key would fail validation and lose the whole
195                // report rather than just the tag.
196                envSource: source,
197                envKey: String(key).slice(0, 64)
198              }),
199              keepalive: true
200            }).catch(function() {});
201          } catch (e) { /* Swallow — advisory telemetry must never break an app */ }
202        }
203        window.__genesisReportDeadEnv = reportDeadEnv;
204        // Drain anything the bundle's banner queued. This script is a classic
205        // inline script and the bundle is a deferred module, so in practice the
206        // reporter wins the race; the queue is what makes that not a matter of
207        // luck (and covers an app whose HTML predates this script).
208        try {
209          var queued = window.__genesisDeadEnvQueue;
210          if (queued) {
211            window.__genesisDeadEnvQueue = [];
212            for (var qi = 0; qi < queued.length; qi++) reportDeadEnv(queued[qi][0], queued[qi][1]);
213          }
214        } catch (e) { /* Ignore. */ }
215      })();
216</script>
216<div id="root"></div>
216<script>
217  (function() {
218    if (typeof window === 'undefined' || typeof document === 'undefined') {
219      return;
220    }
221    if (typeof window.gtag === 'function') {
222      return;
223    }
224    window.dataLayer = window.dataLayer || [];
225    function gtag(){window.dataLayer.push(arguments);}
226    window.gtag = gtag;
227    gtag('js', new Date());
228    gtag('config', 'G-WWJTNN1SFE');
229    const script = document.createElement('script');
230    script.async = true;
231    script.src = 'https://www.googletagmanager.com/gtag/js?id=G-WWJTNN1SFE';
232    document.head.appendChild(script);
233  })();
234</script>
234
235
236<style>
237  @import url('https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600&display=swap');
238
239  :root {
240    /* Onboarding Black Glass - optimized for dark mode */
241    --badge-black: rgba(0, 0, 0, 0.75);
242    --badge-black-hover: rgba(0, 0, 0, 0.85);
243    --badge-text: rgba(255, 255, 255, 0.9);
244    --badge-text-hover: rgba(255, 255, 255, 1);
245    --badge-border: rgba(255, 255, 255, 0.15);
246    --badge-border-hover: rgba(255, 255, 255, 0.25);
247    --badge-shadow: rgba(0, 0, 0, 0.4);
248    
249    /* Rainbow gradient colors from Taskade Upgrade button */
250    --rainbow-color-1: #5cb2f9;  /* Blue */
251    --rainbow-color-2: #8787f7;  /* Purple-Blue */
252    --rainbow-color-3: #a774f7;  /* Purple */
253    --rainbow-color-4: #e376a8;  /* Pink */
254    --rainbow-color-5: #eb7551;  /* Orange */
255    --rainbow-color-6: #19bd59;  /* Green */
256    --rainbow-color-7: #dee325;  /* Yellow-Green */
257    --rainbow-color-8: #e32545;  /* Red */
258    
259    /* Cinematic easing */
260    --ease-cinematic: cubic-bezier(0.22, 1, 0.36, 1);
261    --ease-cinematic-slow: cubic-bezier(0.16, 1, 0.3, 1);
262  }
263
264  [data-theme="light"] {
265    --badge-black: rgba(0, 0, 0, 0.8);
266    --badge-black-hover: rgba(0, 0, 0, 0.9);
267    --badge-text: rgba(255, 255, 255, 0.95);
268    --badge-text-hover: rgba(255, 255, 255, 1);
269    --badge-border: rgba(255, 255, 255, 0.2);
270    --badge-border-hover: rgba(255, 255, 255, 0.3);
271    --badge-shadow: rgba(0, 0, 0, 0.5);
272  }
273
274  @media (prefers-color-scheme: light) {
275    :root {
276      --badge-black: rgba(0, 0, 0, 0.8);
277      --badge-black-hover: rgba(0, 0, 0, 0.9);
278      --badge-text: rgba(255, 255, 255, 0.95);
279      --badge-text-hover: rgba(255, 255, 255, 1);
280      --badge-border: rgba(255, 255, 255, 0.2);
281      --badge-border-hover: rgba(255, 255, 255, 0.3);
282      --badge-shadow: rgba(0, 0, 0, 0.5);
283    }
284  }
285
286  /* Onboarding Black Glass Badge - Bottom Center Position */
287  #taskade-badge {
288    position: fixed;
289    bottom: 24px;
290    left: 50%;
291    transform: translateX(-50%) scale(0.9);
292    z-index: 10001;
293    font-family: 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;
294    animation: badgeGeistFadeIn 1.2s var(--ease-cinematic) forwards;
295    opacity: 0;
296    display: inline-flex;
297    align-items: center;
298    gap: 7px;
299    padding: 7px 12px;
300    font-size: 0.8125rem;
301    font-weight: 500;
302    letter-spacing: -0.01em;
303    line-height: 1;
304    color: var(--badge-text);
305    text-decoration: none;
306    background: var(--badge-black);
307    border: 1px solid var(--badge-border);
308    border-radius: 9999px;
309    backdrop-filter: blur(20px) saturate(1.4);
310    -webkit-backdrop-filter: blur(20px) saturate(1.4);
311    cursor: pointer;
312    transition: all 0.3s var(--ease-cinematic);
313    overflow: hidden;
314    will-change: transform, box-shadow;
315    white-space: nowrap;
316  }
317
318  #taskade-badge a {
319    display: flex;
320    align-items: center;
321    gap: 7px;
322    color: inherit;
323    text-decoration: none;
324  }
325
326  /* Default state with subtle rainbow glow */
327  #taskade-badge {
328    box-shadow: 
329      0 4px 16px var(--badge-shadow),
330      0 0 8px rgba(227, 118, 168, 0.2),
331      0 0 16px rgba(163, 116, 247, 0.15);
332  }
333
334  /* Black glass hover with enhanced rainbow glow */
335  #taskade-badge:hover {
336    background: var(--badge-black-hover);
337    border-color: var(--badge-border-hover);
338    color: var(--badge-text-hover);
339    box-shadow: 
340      0 8px 24px var(--badge-shadow),
341      0 0 16px rgba(227, 118, 168, 0.4),
342      0 0 32px rgba(163, 116, 247, 0.3),
343      inset 0 1px 0 rgba(255, 255, 255, 0.12);
344    transform: translateY(-3px) scale(1.03);
345  }
346
347  /* Taskade sheep mascot - optimized for dark mode */
348  #taskade-badge #taskade-logo {
349    width: 16px;
350    height: 16px;
351    flex-shrink: 0;
352    opacity: 0.95;
353    transition: all 0.3s var(--ease-cinematic);
354    filter: invert(1) brightness(1.1) contrast(1.05);
355  }
356
357  #taskade-badge:hover #taskade-logo {
358    opacity: 1;
359    transform: scale(1.08) rotate(-2deg);
360    filter: invert(1) brightness(1.2) contrast(1.1);
361  }
362
363  /* Light mode adjustments */
364  [data-theme="light"] #taskade-badge #taskade-logo {
365    filter: invert(0) brightness(1.1);
366  }
367
368  [data-theme="light"] #taskade-badge:hover #taskade-logo {
369    filter: invert(0) brightness(1.2);
370  }
371
372  @media (prefers-color-scheme: light) {
373    :root #taskade-badge #taskade-logo {
374      filter: invert(0) brightness(1.1);
375    }
376
377    :root #taskade-badge:hover #taskade-logo {
378      filter: invert(0) brightness(1.2);
379    }
380  }
381
382  /* Geist typography */
383  #taskade-badge .badge-text {
384    font-weight: 500;
385    letter-spacing: 0.005em;
386    transition: all 0.3s var(--ease-cinematic);
387    -webkit-font-smoothing: antialiased;
388    -moz-osx-font-smoothing: grayscale;
389  }
390
391  #taskade-badge.hidden {
392    display: none;
393  }
394
395  /* Geist fade-in animation */
396  @keyframes badgeGeistFadeIn {
397    0% {
398      opacity: 0;
399      transform: translateX(-50%) translateY(8px) scale(0.85);
400      filter: blur(6px);
401    }
402    60% {
403      opacity: 0.7;
404      filter: blur(2px);
405    }
406    100% {
407      opacity: 1;
408      transform: translateX(-50%) translateY(0) scale(0.9);
409      filter: blur(0);
410    }
411  }
412
413  /* Responsive */
414  @media (max-width: 768px) {
415    #taskade-badge {
416      bottom: 80px; /* Above mobile nav/TAA chat */
417      left: 50%;
418      transform: translateX(-50%) scale(0.85);
419      padding: 6px 10px;
420      font-size: 0.75rem;
421      gap: 5px;
422    }
423
424    #taskade-badge #taskade-logo {
425      width: 14px;
426      height: 14px;
427    }
428  }
429
430  /* Reduced motion */
431  @media (prefers-reduced-motion: reduce) {
432    #taskade-badge {
433      animation: none;
434      opacity: 1;
435    }
436
437    #taskade-badge a,
438    #taskade-badge #taskade-logo,
439    #taskade-badge .badge-text {
440      transition: none;
441      animation: none;
442    }
443  }
444
445  /* High contrast */
446  @media (prefers-contrast: high) {
447    #taskade-badge a {
448      border-width: 2px;
449      border-color: currentColor;
450    }
451  }
452
453  /* Hide when printing */
454  @media print {
455    #taskade-badge {
456      display: none !important;
457    }
458  }
459</style>
460
461<div id="taskade-badge" data-badge-mode="powered_by">
462  <a href="https://www.taskade.com/signup?utm_source=genesis_badge&utm_medium=app_badge&utm_campaign=p
462owered_by&utm_content=hukxgm8wfgw2y2mq" target="_blank" rel="noopener noreferrer">
463    <img id="taskade-logo" src="./_assets/logo.png" alt="Taskade" />
464    <span class="badge-text" data-community-text="Edit in Taskade" data-default-text="Powered by Taskade">Powered by Taskade</span>
465  </a>
466</div>
467
468<script>
469  (function() {
470    // Geist theme detection - matching wait.html
471    function applyTheme() {
472      const urlParams = new URLSearchParams(window.location.search);
473      let theme = urlParams.get('theme');
474      
475      if (!theme) {
476        try {
477          if (window.parent !== window) {
478            const parentTheme = window.parent.document.documentElement.getAttribute('data-theme');                                                              
479            if (parentTheme) theme = parentTheme;
480          }
481        } catch (e) {}
482        
483        if (!theme) {
484          theme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';                                                                
485        }
486      }
487      
488      document.documentElement.setAttribute('data-theme', theme === 'light' ? 'light' : 'dark');                                                                
489    }
490
491    // Apply theme immediately
492    applyTheme();
493
494    // Theme change listener
495    window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', (e) => {                                                                      
496      const urlParams = new URLSearchParams(window.location.search);
497      if (!urlParams.get('theme')) {
498        document.documentElement.setAttribute('data-theme', e.matches ? 'light' : 'dark');                                                                      
499      }
500    });
501
502    // Analytics tracking and postMessage communication
503    const badgeLink = document.querySelector('#taskade-badge a');
504    if (badgeLink) {
505      let parentOrigin = '*';
506      let parentHostname = '';
507      if (document.referrer) {
508        try {
509          const referrerUrl = new URL(document.referrer);
510          parentOrigin = referrerUrl.origin;
511          parentHostname = referrerUrl.hostname;
512        } catch (err) {
513          parentOrigin = '*';
514          parentHostname = '';
515        }
516      }
517      // Taskade itself is framing us (the share page at /app/{id}, which
518      // iframes the app). parentOrigin stays '*' when there is no usable
519      // referrer, and then the framer is unknowable.
520      const framedByTaskade =
521        parentOrigin !== '*' &&
522        (parentHostname === 'taskade.com' || parentHostname.endsWith('.taskade.com'));
523
524      const badge = document.getElementById('taskade-badge');
525      const badgeText = document.querySelector('#taskade-badge .badge-text');
526      const communityText = badgeText ? badgeText.getAttribute('data-community-text') : null;
527      const badgeHref = badgeLink.getAttribute('href') || '';
528      const badgeMode = badge ? badge.getAttribute('data-badge-mode') : null;
529      const isCommunityShare =
530        badgeMode === 'edit' ||
531        (badgeText &&
532          communityText &&
533          badgeText.textContent &&
534          badgeText.textContent.trim() === communityText) ||
535        badgeHref.indexOf('/app/') !== -1;
536
537      if (window.parent !== window) {
538        // Hide only when embedded: on the standalone domain this badge IS the
539        // viral return path into Taskade, so it must stay visible there.
540        // Scope note, two independent reasons to hide inside a frame:
541        // 1. The Taskade share page frames the app and already renders its own
542        //    Clone CTA, so ANY badge mode is a duplicate there. A buyer of a
543        //    non-template listing stays on /app/{id} and sees exactly that.
544        // 2. An edit-mode badge hides in any frame, because its /app/{id} link
545        //    just points back at the framing page.
546        // A powered_by badge in an unrelated third-party embed still renders -
547        // there it is the only way back to Taskade. With no referrer the
548        // framer is unknowable, so only the mode-based reason applies.
549        if ((isCommunityShare || framedByTaskade) && badge) {
550          badge.classList.add('hidden');
551        }
552
553        const notifyParent = () => {
554          window.parent.postMessage(
555            {
556              type: 'TASKADE_BADGE_MODE',
557              source: 'taskade_badge',
558              mode: isCommunityShare ? 'edit' : 'powered_by',
559            },
560            parentOrigin
561          );
562        };
563
564        try {
565          notifyParent();
566          setTimeout(notifyParent, 500);
567        } catch (err) {
568          // Ignore postMessage failures.
569        }
570      }
571
572      badgeLink.addEventListener('click', function() {
573        // Track badge engagement
574        if (typeof window.gtag === 'function') {
575          window.gtag('event', 'genesis_badge_clicked', {
576            event_category: 'engagement',
577            event_label: 'edit_in_taskade'
578          });
579        }
580
581      });
582    }
583
584  })();
585</script>
vendor: 1 bytes, line 585
585
586<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"8d4254f20c524f6fbf6ecde0b2c89fb4","spa":2}' crossorigin="anonymous"></script>
586
587</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.