@yoamigo.com/core 0.3.1 → 0.3.3
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/{MarkdownText-BUTYfqXS.d.ts → MarkdownText-Nvkeyr1z.d.ts} +46 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +619 -180
- package/dist/lib.js +30 -5
- package/dist/plugin.js +6 -0
- package/dist/prod.d.ts +41 -2
- package/dist/prod.js +295 -4
- package/package.json +1 -1
package/dist/lib.js
CHANGED
|
@@ -116,6 +116,9 @@ var BuilderSelectionManager = class {
|
|
|
116
116
|
elementMap = /* @__PURE__ */ new Map();
|
|
117
117
|
// Current selections from parent (for re-rendering on mode change)
|
|
118
118
|
currentSelections = [];
|
|
119
|
+
// Throttle screenshot captures to prevent overlapping
|
|
120
|
+
lastCaptureTime = 0;
|
|
121
|
+
CAPTURE_THROTTLE_MS = 3e3;
|
|
119
122
|
constructor() {
|
|
120
123
|
if (window.parent === window) {
|
|
121
124
|
console.log("[BuilderSelection] Not in iframe, skipping initialization");
|
|
@@ -239,6 +242,16 @@ var BuilderSelectionManager = class {
|
|
|
239
242
|
});
|
|
240
243
|
};
|
|
241
244
|
handleKeyDown = (e) => {
|
|
245
|
+
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
|
246
|
+
const modifier = isMac ? e.metaKey : e.ctrlKey;
|
|
247
|
+
if (modifier) {
|
|
248
|
+
if (e.key === "=" || e.key === "+" || e.key === "-" || e.key === "0" || e.key === "1") {
|
|
249
|
+
e.preventDefault();
|
|
250
|
+
const normalizedKey = e.key === "=" ? "+" : e.key;
|
|
251
|
+
this.sendToParent({ type: "IFRAME_KEYBOARD_ZOOM", key: normalizedKey });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
242
255
|
if (e.key === "Shift") {
|
|
243
256
|
const activeElement = document.activeElement;
|
|
244
257
|
const isEditing = activeElement?.closest(".ya-text-editing") || activeElement?.closest(".ya-link-editing");
|
|
@@ -555,10 +568,16 @@ var BuilderSelectionManager = class {
|
|
|
555
568
|
/**
|
|
556
569
|
* Capture a full-page screenshot for loading placeholder
|
|
557
570
|
* Uses html2canvas to render the page at reduced quality for smaller file size
|
|
571
|
+
* Throttled to prevent overlapping captures (3 second minimum between captures)
|
|
558
572
|
*/
|
|
559
573
|
async captureFullPageScreenshot() {
|
|
574
|
+
const now = Date.now();
|
|
575
|
+
if (now - this.lastCaptureTime < this.CAPTURE_THROTTLE_MS) {
|
|
576
|
+
console.log("[BuilderSelection] Screenshot throttled");
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
this.lastCaptureTime = now;
|
|
560
580
|
try {
|
|
561
|
-
console.log("[BuilderSelection] Capturing full-page screenshot");
|
|
562
581
|
const html2canvas = (await import("html2canvas-pro")).default;
|
|
563
582
|
const overlays = document.querySelectorAll(".builder-selection-container, #builder-hover-overlay");
|
|
564
583
|
overlays.forEach((el) => {
|
|
@@ -571,14 +590,14 @@ var BuilderSelectionManager = class {
|
|
|
571
590
|
logging: false,
|
|
572
591
|
useCORS: true,
|
|
573
592
|
allowTaint: true,
|
|
574
|
-
backgroundColor:
|
|
593
|
+
backgroundColor: "#ffffff"
|
|
594
|
+
// White background for JPEG (null would render as black)
|
|
575
595
|
});
|
|
576
596
|
overlays.forEach((el) => {
|
|
577
597
|
;
|
|
578
598
|
el.style.display = "";
|
|
579
599
|
});
|
|
580
600
|
const dataUrl = canvas.toDataURL("image/jpeg", 0.6);
|
|
581
|
-
console.log("[BuilderSelection] Full-page screenshot captured, size:", dataUrl.length);
|
|
582
601
|
this.sendToParent({
|
|
583
602
|
type: "SCREENSHOT_READY",
|
|
584
603
|
dataUrl
|
|
@@ -698,12 +717,18 @@ var BuilderSelectionManager = class {
|
|
|
698
717
|
this.selections.set(selectionId, { element, container, badge, border });
|
|
699
718
|
}
|
|
700
719
|
};
|
|
720
|
+
var instance = null;
|
|
701
721
|
function initBuilderSelection() {
|
|
702
722
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
723
|
+
if (instance) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
703
726
|
if (document.readyState === "loading") {
|
|
704
|
-
document.addEventListener("DOMContentLoaded", () =>
|
|
727
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
728
|
+
instance = new BuilderSelectionManager();
|
|
729
|
+
});
|
|
705
730
|
} else {
|
|
706
|
-
new BuilderSelectionManager();
|
|
731
|
+
instance = new BuilderSelectionManager();
|
|
707
732
|
}
|
|
708
733
|
}
|
|
709
734
|
}
|
package/dist/plugin.js
CHANGED
|
@@ -108,6 +108,12 @@ if (import.meta.hot) {
|
|
|
108
108
|
outDir: "dist",
|
|
109
109
|
emptyOutDir: true,
|
|
110
110
|
rollupOptions: {
|
|
111
|
+
onwarn(warning, warn) {
|
|
112
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes('"use client"')) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
warn(warning);
|
|
116
|
+
},
|
|
111
117
|
output: {
|
|
112
118
|
// Output to build/ to avoid confusion with public/assets/ (source images)
|
|
113
119
|
entryFileNames: "build/[name].[hash].js",
|
package/dist/prod.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, u as useContentStore } from './MarkdownText-
|
|
1
|
+
export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, p as parseEmbedUrl, u as useContentStore } from './MarkdownText-Nvkeyr1z.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import React, { CSSProperties, ReactNode } from 'react';
|
|
4
4
|
export { Link, LinkProps, NavigateFunction, Router, RouterProps, useNavigate } from './router.js';
|
|
@@ -127,4 +127,43 @@ interface StaticVideoProps {
|
|
|
127
127
|
declare function serializeVideoValue(value: VideoFieldValue): string;
|
|
128
128
|
declare function StaticVideo({ fieldId, className, aspectRatio: propAspectRatio, objectFit: propObjectFit, loading, defaultValue, fallbackSrc, fallbackPoster, }: StaticVideoProps): react_jsx_runtime.JSX.Element;
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
/**
|
|
131
|
+
* StaticEmbed Component - Production version of YaEmbed
|
|
132
|
+
*
|
|
133
|
+
* Renders embeds statically (Spotify, SoundCloud, Twitter, Instagram, custom).
|
|
134
|
+
* No editing capabilities - pure display.
|
|
135
|
+
*/
|
|
136
|
+
type EmbedType = 'spotify' | 'soundcloud' | 'twitter' | 'instagram' | 'custom';
|
|
137
|
+
interface EmbedFieldValue {
|
|
138
|
+
/** Embed platform type */
|
|
139
|
+
type: EmbedType;
|
|
140
|
+
/** Embed URL or ID (platform-specific) */
|
|
141
|
+
src: string;
|
|
142
|
+
/** Original URL pasted by user (for editing) */
|
|
143
|
+
originalUrl?: string;
|
|
144
|
+
/** CSS aspect-ratio (e.g., "16/9", "1/1") */
|
|
145
|
+
aspectRatio?: string;
|
|
146
|
+
/** Fixed height in pixels (for audio players) */
|
|
147
|
+
height?: number;
|
|
148
|
+
/** Spotify-specific: content type */
|
|
149
|
+
spotifyType?: 'track' | 'album' | 'playlist' | 'episode' | 'show';
|
|
150
|
+
}
|
|
151
|
+
interface StaticEmbedProps {
|
|
152
|
+
fieldId: string;
|
|
153
|
+
className?: string;
|
|
154
|
+
/** Default aspect ratio from props */
|
|
155
|
+
aspectRatio?: string;
|
|
156
|
+
/** Max width constraint */
|
|
157
|
+
maxWidth?: number;
|
|
158
|
+
/** Loading strategy */
|
|
159
|
+
loading?: 'lazy' | 'eager';
|
|
160
|
+
/** Default embed value (used when nothing in content store) */
|
|
161
|
+
defaultValue?: EmbedFieldValue;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Serialize embed field value for storage
|
|
165
|
+
*/
|
|
166
|
+
declare function serializeEmbedValue(value: EmbedFieldValue): string;
|
|
167
|
+
declare function StaticEmbed({ fieldId, className, aspectRatio: propAspectRatio, maxWidth, loading, defaultValue, }: StaticEmbedProps): react_jsx_runtime.JSX.Element;
|
|
168
|
+
|
|
169
|
+
export { type BackgroundConfig, type BackgroundImageConfig, type EmbedFieldValue, type EmbedType, type OverlayConfig, SafeHtml, type SafeHtmlProps, StaticContainer, type StaticContainerProps, StaticEmbed, type StaticEmbedProps, StaticLink, type StaticLinkProps, StaticVideo, type StaticVideoProps, type VideoFieldValue, StaticContainer as YaContainer, type StaticContainerProps as YaContainerProps, StaticEmbed as YaEmbed, type StaticEmbedProps as YaEmbedProps, StaticLink as YaLink, type StaticLinkProps as YaLinkProps, StaticVideo as YaVideo, type StaticVideoProps as YaVideoProps, parseBackgroundConfig, serializeBackgroundConfig, serializeEmbedValue, serializeVideoValue };
|
package/dist/prod.js
CHANGED
|
@@ -587,12 +587,299 @@ function StaticVideo({
|
|
|
587
587
|
);
|
|
588
588
|
}
|
|
589
589
|
|
|
590
|
+
// src/components/StaticEmbed.tsx
|
|
591
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
592
|
+
import { jsx as jsx9, jsxs } from "react/jsx-runtime";
|
|
593
|
+
function parseEmbedValue(value) {
|
|
594
|
+
if (!value) {
|
|
595
|
+
return { type: "custom", src: "" };
|
|
596
|
+
}
|
|
597
|
+
try {
|
|
598
|
+
const parsed = JSON.parse(value);
|
|
599
|
+
if (typeof parsed === "object" && parsed.src) {
|
|
600
|
+
return {
|
|
601
|
+
type: parsed.type || "custom",
|
|
602
|
+
...parsed
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
} catch {
|
|
606
|
+
}
|
|
607
|
+
return { type: "custom", src: value, originalUrl: value };
|
|
608
|
+
}
|
|
609
|
+
function serializeEmbedValue(value) {
|
|
610
|
+
return JSON.stringify(value);
|
|
611
|
+
}
|
|
612
|
+
function buildSpotifyEmbedUrl(src) {
|
|
613
|
+
return `https://open.spotify.com/embed/${src}?utm_source=generator&theme=0`;
|
|
614
|
+
}
|
|
615
|
+
function buildSoundCloudEmbedUrl(src) {
|
|
616
|
+
return `https://w.soundcloud.com/player/?url=${encodeURIComponent(src)}&color=%23ff5500&auto_play=false&hide_related=true&show_comments=false&show_user=true&show_reposts=false&show_teaser=false`;
|
|
617
|
+
}
|
|
618
|
+
function buildInstagramEmbedUrl(shortcode) {
|
|
619
|
+
return `https://www.instagram.com/p/${shortcode}/embed`;
|
|
620
|
+
}
|
|
621
|
+
function StaticEmbed({
|
|
622
|
+
fieldId,
|
|
623
|
+
className,
|
|
624
|
+
aspectRatio: propAspectRatio,
|
|
625
|
+
maxWidth,
|
|
626
|
+
loading = "lazy",
|
|
627
|
+
defaultValue
|
|
628
|
+
}) {
|
|
629
|
+
const { getValue } = useContentStore();
|
|
630
|
+
const containerRef = useRef2(null);
|
|
631
|
+
const [isInView, setIsInView] = useState2(loading === "eager");
|
|
632
|
+
const rawValue = getValue(fieldId);
|
|
633
|
+
const parsedValue = parseEmbedValue(rawValue);
|
|
634
|
+
const embedData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
|
|
635
|
+
const src = embedData.src || "";
|
|
636
|
+
const embedType = embedData.type || "custom";
|
|
637
|
+
const height = embedData.height;
|
|
638
|
+
const aspectRatio = embedData.aspectRatio || propAspectRatio || "16/9";
|
|
639
|
+
useEffect2(() => {
|
|
640
|
+
if (loading === "eager" || isInView) return;
|
|
641
|
+
const observer = new IntersectionObserver(
|
|
642
|
+
(entries) => {
|
|
643
|
+
if (entries[0]?.isIntersecting) {
|
|
644
|
+
setIsInView(true);
|
|
645
|
+
observer.disconnect();
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
{ rootMargin: "200px" }
|
|
649
|
+
);
|
|
650
|
+
if (containerRef.current) {
|
|
651
|
+
observer.observe(containerRef.current);
|
|
652
|
+
}
|
|
653
|
+
return () => observer.disconnect();
|
|
654
|
+
}, [loading, isInView]);
|
|
655
|
+
const renderEmbed = () => {
|
|
656
|
+
if (!src) return null;
|
|
657
|
+
if (!isInView && loading === "lazy") {
|
|
658
|
+
return /* @__PURE__ */ jsx9("div", { className: "ya-embed-placeholder", style: { aspectRatio } });
|
|
659
|
+
}
|
|
660
|
+
if (embedType === "spotify" && src) {
|
|
661
|
+
const embedUrl = buildSpotifyEmbedUrl(src);
|
|
662
|
+
return /* @__PURE__ */ jsx9(
|
|
663
|
+
"iframe",
|
|
664
|
+
{
|
|
665
|
+
src: embedUrl,
|
|
666
|
+
style: {
|
|
667
|
+
width: "100%",
|
|
668
|
+
height: height ? `${height}px` : "100%",
|
|
669
|
+
border: "none",
|
|
670
|
+
borderRadius: "12px"
|
|
671
|
+
},
|
|
672
|
+
allow: "autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture",
|
|
673
|
+
loading,
|
|
674
|
+
title: "Spotify embed"
|
|
675
|
+
}
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
if (embedType === "soundcloud" && src) {
|
|
679
|
+
const embedUrl = buildSoundCloudEmbedUrl(src);
|
|
680
|
+
return /* @__PURE__ */ jsx9(
|
|
681
|
+
"iframe",
|
|
682
|
+
{
|
|
683
|
+
src: embedUrl,
|
|
684
|
+
style: {
|
|
685
|
+
width: "100%",
|
|
686
|
+
height: height ? `${height}px` : "166px",
|
|
687
|
+
border: "none"
|
|
688
|
+
},
|
|
689
|
+
allow: "autoplay",
|
|
690
|
+
loading,
|
|
691
|
+
title: "SoundCloud embed"
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
if (embedType === "twitter" && src) {
|
|
696
|
+
return /* @__PURE__ */ jsxs("div", { className: "ya-embed-twitter", children: [
|
|
697
|
+
/* @__PURE__ */ jsx9("blockquote", { className: "twitter-tweet", "data-dnt": "true", children: /* @__PURE__ */ jsx9("a", { href: embedData.originalUrl || `https://twitter.com/i/status/${src}`, children: "Loading tweet..." }) }),
|
|
698
|
+
/* @__PURE__ */ jsx9(TwitterWidgetLoader, {})
|
|
699
|
+
] });
|
|
700
|
+
}
|
|
701
|
+
if (embedType === "instagram" && src) {
|
|
702
|
+
const embedUrl = buildInstagramEmbedUrl(src);
|
|
703
|
+
return /* @__PURE__ */ jsx9(
|
|
704
|
+
"iframe",
|
|
705
|
+
{
|
|
706
|
+
src: embedUrl,
|
|
707
|
+
style: {
|
|
708
|
+
width: "100%",
|
|
709
|
+
height: "100%",
|
|
710
|
+
aspectRatio,
|
|
711
|
+
border: "none",
|
|
712
|
+
minHeight: "400px"
|
|
713
|
+
},
|
|
714
|
+
allow: "encrypted-media",
|
|
715
|
+
loading,
|
|
716
|
+
title: "Instagram embed"
|
|
717
|
+
}
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
if (embedType === "custom" && src) {
|
|
721
|
+
return /* @__PURE__ */ jsx9(
|
|
722
|
+
"iframe",
|
|
723
|
+
{
|
|
724
|
+
src,
|
|
725
|
+
style: {
|
|
726
|
+
width: "100%",
|
|
727
|
+
height: "100%",
|
|
728
|
+
border: "none",
|
|
729
|
+
aspectRatio
|
|
730
|
+
},
|
|
731
|
+
sandbox: "allow-scripts allow-same-origin allow-popups allow-forms",
|
|
732
|
+
loading,
|
|
733
|
+
title: "Embedded content"
|
|
734
|
+
}
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
return null;
|
|
738
|
+
};
|
|
739
|
+
const wrapperStyle = {
|
|
740
|
+
aspectRatio: height ? void 0 : aspectRatio,
|
|
741
|
+
height: height ? `${height}px` : void 0,
|
|
742
|
+
maxWidth: maxWidth ? `${maxWidth}px` : void 0
|
|
743
|
+
};
|
|
744
|
+
return /* @__PURE__ */ jsx9(
|
|
745
|
+
"div",
|
|
746
|
+
{
|
|
747
|
+
ref: containerRef,
|
|
748
|
+
className: `ya-embed-wrapper ${className || ""}`,
|
|
749
|
+
style: wrapperStyle,
|
|
750
|
+
"data-field-id": fieldId,
|
|
751
|
+
"data-embed-type": embedType,
|
|
752
|
+
children: renderEmbed()
|
|
753
|
+
}
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
function TwitterWidgetLoader() {
|
|
757
|
+
useEffect2(() => {
|
|
758
|
+
if (window.twttr?.widgets) {
|
|
759
|
+
;
|
|
760
|
+
window.twttr.widgets.load();
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (document.getElementById("twitter-wjs")) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const script = document.createElement("script");
|
|
767
|
+
script.id = "twitter-wjs";
|
|
768
|
+
script.src = "https://platform.twitter.com/widgets.js";
|
|
769
|
+
script.async = true;
|
|
770
|
+
document.body.appendChild(script);
|
|
771
|
+
}, []);
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/components/YaEmbed.tsx
|
|
776
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
777
|
+
|
|
778
|
+
// #style-inject:#style-inject
|
|
779
|
+
function styleInject(css, { insertAt } = {}) {
|
|
780
|
+
if (!css || typeof document === "undefined") return;
|
|
781
|
+
const head = document.head || document.getElementsByTagName("head")[0];
|
|
782
|
+
const style = document.createElement("style");
|
|
783
|
+
style.type = "text/css";
|
|
784
|
+
if (insertAt === "top") {
|
|
785
|
+
if (head.firstChild) {
|
|
786
|
+
head.insertBefore(style, head.firstChild);
|
|
787
|
+
} else {
|
|
788
|
+
head.appendChild(style);
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
head.appendChild(style);
|
|
792
|
+
}
|
|
793
|
+
if (style.styleSheet) {
|
|
794
|
+
style.styleSheet.cssText = css;
|
|
795
|
+
} else {
|
|
796
|
+
style.appendChild(document.createTextNode(css));
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/components/ya-embed.css
|
|
801
|
+
styleInject('.ya-embed-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n.ya-embed-wrapper iframe {\n display: block;\n width: 100%;\n height: 100%;\n}\n.ya-embed-container {\n position: relative;\n display: block;\n width: 100%;\n min-width: 80px;\n min-height: 80px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-embed-container iframe {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.ya-embed-editable {\n cursor: pointer;\n}\n.ya-embed-editable:hover {\n outline: 2px dashed var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-selected {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-embed-editable:hover .ya-embed-overlay {\n opacity: 1;\n}\n.ya-embed-selected .ya-embed-overlay {\n opacity: 0;\n}\n.ya-embed-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-embed-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-embed-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n.ya-embed-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 100%;\n min-height: 120px;\n background: #f3f4f6;\n border: 2px dashed #d1d5db;\n border-radius: 8px;\n color: #6b7280;\n font-size: 14px;\n}\n.ya-embed-placeholder img {\n width: 64px;\n height: auto;\n opacity: 0.5;\n}\n@keyframes ya-embed-success {\n 0% {\n outline-color: var(--color-primary, #d4a574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #d4a574);\n outline-width: 2px;\n }\n}\n.ya-embed-success {\n animation: ya-embed-success 0.4s ease;\n}\n.ya-embed-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-embed-shimmer 1.5s infinite;\n}\n@keyframes ya-embed-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-embed-container:focus {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-embed-container:focus-visible {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-small .ya-embed-overlay {\n display: none;\n}\n.ya-embed-twitter {\n min-height: 200px;\n}\n.ya-embed-twitter .twitter-tweet {\n margin: 0 auto !important;\n}\n.ya-embed-wrapper[data-embed-type=spotify],\n.ya-embed-container[data-embed-type=spotify] {\n min-height: 80px;\n}\n.ya-embed-wrapper[data-embed-type=soundcloud],\n.ya-embed-container[data-embed-type=soundcloud] {\n min-height: 166px;\n}\n.ya-embed-wrapper[data-embed-type=instagram] iframe,\n.ya-embed-container[data-embed-type=instagram] iframe {\n min-height: 400px;\n}\n');
|
|
802
|
+
|
|
803
|
+
// src/components/YaEmbed.tsx
|
|
804
|
+
import { jsx as jsx10, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
805
|
+
function parseEmbedUrl(url) {
|
|
806
|
+
if (!url) return null;
|
|
807
|
+
const trimmedUrl = url.trim();
|
|
808
|
+
const spotifyMatch = trimmedUrl.match(
|
|
809
|
+
/open\.spotify\.com\/(track|album|playlist|episode|show)\/([a-zA-Z0-9]+)/
|
|
810
|
+
);
|
|
811
|
+
if (spotifyMatch) {
|
|
812
|
+
const spotifyType = spotifyMatch[1];
|
|
813
|
+
const spotifyId = spotifyMatch[2];
|
|
814
|
+
const height = spotifyType === "track" ? 152 : 352;
|
|
815
|
+
return {
|
|
816
|
+
type: "spotify",
|
|
817
|
+
src: `${spotifyType}/${spotifyId}`,
|
|
818
|
+
originalUrl: trimmedUrl,
|
|
819
|
+
height,
|
|
820
|
+
spotifyType
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
const soundcloudMatch = trimmedUrl.match(/soundcloud\.com\/([^/]+)\/([^/?]+)/);
|
|
824
|
+
if (soundcloudMatch) {
|
|
825
|
+
return {
|
|
826
|
+
type: "soundcloud",
|
|
827
|
+
src: trimmedUrl,
|
|
828
|
+
// SoundCloud embeds use full URL
|
|
829
|
+
originalUrl: trimmedUrl,
|
|
830
|
+
height: 166
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
const twitterMatch = trimmedUrl.match(/(?:twitter\.com|x\.com)\/\w+\/status\/(\d+)/);
|
|
834
|
+
if (twitterMatch) {
|
|
835
|
+
return {
|
|
836
|
+
type: "twitter",
|
|
837
|
+
src: twitterMatch[1],
|
|
838
|
+
// Tweet ID
|
|
839
|
+
originalUrl: trimmedUrl,
|
|
840
|
+
aspectRatio: "1/1"
|
|
841
|
+
// Twitter embeds are roughly square
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
const instagramMatch = trimmedUrl.match(/instagram\.com\/(?:p|reel)\/([a-zA-Z0-9_-]+)/);
|
|
845
|
+
if (instagramMatch) {
|
|
846
|
+
return {
|
|
847
|
+
type: "instagram",
|
|
848
|
+
src: instagramMatch[1],
|
|
849
|
+
// Post shortcode
|
|
850
|
+
originalUrl: trimmedUrl,
|
|
851
|
+
aspectRatio: "1/1"
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
if (trimmedUrl.startsWith("https://")) {
|
|
855
|
+
if (trimmedUrl.startsWith("javascript:") || trimmedUrl.startsWith("data:") || trimmedUrl.includes("<script")) {
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
return {
|
|
859
|
+
type: "custom",
|
|
860
|
+
src: trimmedUrl,
|
|
861
|
+
originalUrl: trimmedUrl,
|
|
862
|
+
aspectRatio: "16/9"
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
var PLACEHOLDER_SVG = `data:image/svg+xml,${encodeURIComponent(`
|
|
868
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="225" viewBox="0 0 400 225">
|
|
869
|
+
<rect fill="#e5e7eb" width="400" height="225"/>
|
|
870
|
+
<g fill="#9ca3af" transform="translate(175, 87)">
|
|
871
|
+
<rect x="5" y="5" width="40" height="30" rx="4" stroke="currentColor" stroke-width="2" fill="none"/>
|
|
872
|
+
<path d="M15 15 L25 22 L15 29 Z" fill="currentColor"/>
|
|
873
|
+
</g>
|
|
874
|
+
</svg>
|
|
875
|
+
`)}`;
|
|
876
|
+
|
|
590
877
|
// src/router/Link.tsx
|
|
591
878
|
import { Link as WouterLink } from "wouter";
|
|
592
|
-
import { jsx as
|
|
879
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
593
880
|
function Link({ to, href, children, className, onClick, replace, ...props }) {
|
|
594
881
|
const target = href ?? to ?? "/";
|
|
595
|
-
return /* @__PURE__ */
|
|
882
|
+
return /* @__PURE__ */ jsx11(WouterLink, { href: target, className, onClick, replace, ...props, children });
|
|
596
883
|
}
|
|
597
884
|
|
|
598
885
|
// src/router/useNavigate.ts
|
|
@@ -611,7 +898,7 @@ function useNavigate() {
|
|
|
611
898
|
|
|
612
899
|
// src/router/Router.tsx
|
|
613
900
|
import { Router as WouterRouter } from "wouter";
|
|
614
|
-
import { jsx as
|
|
901
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
615
902
|
function detectBasename() {
|
|
616
903
|
if (typeof window === "undefined") return "";
|
|
617
904
|
const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
|
|
@@ -626,7 +913,7 @@ function detectBasename() {
|
|
|
626
913
|
}
|
|
627
914
|
function Router({ children, base }) {
|
|
628
915
|
const basename = base ?? detectBasename();
|
|
629
|
-
return /* @__PURE__ */
|
|
916
|
+
return /* @__PURE__ */ jsx12(WouterRouter, { base: basename, children });
|
|
630
917
|
}
|
|
631
918
|
|
|
632
919
|
// src/router/index.ts
|
|
@@ -639,12 +926,14 @@ export {
|
|
|
639
926
|
Router,
|
|
640
927
|
SafeHtml,
|
|
641
928
|
StaticContainer,
|
|
929
|
+
StaticEmbed,
|
|
642
930
|
MpImage as StaticImage,
|
|
643
931
|
StaticLink,
|
|
644
932
|
MpText as StaticText,
|
|
645
933
|
StaticVideo,
|
|
646
934
|
Switch,
|
|
647
935
|
StaticContainer as YaContainer,
|
|
936
|
+
StaticEmbed as YaEmbed,
|
|
648
937
|
MpImage as YaImage,
|
|
649
938
|
StaticLink as YaLink,
|
|
650
939
|
MpText as YaText,
|
|
@@ -654,9 +943,11 @@ export {
|
|
|
654
943
|
getContent,
|
|
655
944
|
hasContent,
|
|
656
945
|
parseBackgroundConfig,
|
|
946
|
+
parseEmbedUrl,
|
|
657
947
|
registerContent,
|
|
658
948
|
resolveAssetUrl,
|
|
659
949
|
serializeBackgroundConfig,
|
|
950
|
+
serializeEmbedValue,
|
|
660
951
|
serializeVideoValue,
|
|
661
952
|
setAssetResolver,
|
|
662
953
|
useContentStore,
|