tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
27
pulls
pipelines
use iframely for urls in embed block editor
awarm.space
3 months ago
cb9348fb
f3e2a86d
+65
-16
1 changed file
expand all
collapse all
unified
split
components
Blocks
EmbedBlock.tsx
+65
-16
components/Blocks/EmbedBlock.tsx
···
10
import { Input } from "components/Input";
11
import { isUrl } from "src/utils/isURL";
12
import { elementId } from "src/utils/elementId";
13
-
import { deleteBlock } from "./DeleteBlock";
14
import { focusBlock } from "src/utils/focusBlock";
15
import { useDrag } from "src/hooks/useDrag";
16
import { BlockEmbedSmall } from "components/Icons/BlockEmbedSmall";
17
import { CheckTiny } from "components/Icons/CheckTiny";
0
0
0
0
0
18
19
export const EmbedBlock = (props: BlockProps & { preview?: boolean }) => {
20
let { permissions } = useEntitySetContext();
···
132
133
let entity_set = useEntitySetContext();
134
let [linkValue, setLinkValue] = useState("");
0
135
let { rep } = useReplicache();
136
let submit = async () => {
137
let entity = props.entityID;
···
149
}
150
let link = linkValue;
151
if (!linkValue.startsWith("http")) link = `https://${linkValue}`;
152
-
// these mutations = simpler subset of addLinkBlock
153
if (!rep) return;
154
-
await rep.mutate.assertFact({
155
-
entity: entity,
156
-
attribute: "block/type",
157
-
data: { type: "block-type-union", value: "embed" },
158
-
});
159
-
await rep?.mutate.assertFact({
160
-
entity: entity,
161
-
attribute: "embed/url",
162
-
data: {
163
-
type: "string",
164
-
value: link,
165
-
},
166
-
});
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
167
};
168
let smoker = useSmoker();
169
···
171
<form
172
onSubmit={(e) => {
173
e.preventDefault();
0
174
let rect = document
175
.getElementById("embed-block-submit")
176
?.getBoundingClientRect();
···
212
<button
213
type="submit"
214
id="embed-block-submit"
0
215
className={`p-1 ${isSelected && !isLocked ? "text-accent-contrast" : "text-border"}`}
216
onMouseDown={(e) => {
217
e.preventDefault();
0
218
if (!linkValue || linkValue === "") {
219
smoker({
220
error: true,
···
234
submit();
235
}}
236
>
237
-
<CheckTiny />
238
</button>
239
</div>
240
</form>
···
10
import { Input } from "components/Input";
11
import { isUrl } from "src/utils/isURL";
12
import { elementId } from "src/utils/elementId";
0
13
import { focusBlock } from "src/utils/focusBlock";
14
import { useDrag } from "src/hooks/useDrag";
15
import { BlockEmbedSmall } from "components/Icons/BlockEmbedSmall";
16
import { CheckTiny } from "components/Icons/CheckTiny";
17
+
import { DotLoader } from "components/utils/DotLoader";
18
+
import {
19
+
LinkPreviewBody,
20
+
LinkPreviewMetadataResult,
21
+
} from "app/api/link_previews/route";
22
23
export const EmbedBlock = (props: BlockProps & { preview?: boolean }) => {
24
let { permissions } = useEntitySetContext();
···
136
137
let entity_set = useEntitySetContext();
138
let [linkValue, setLinkValue] = useState("");
139
+
let [loading, setLoading] = useState(false);
140
let { rep } = useReplicache();
141
let submit = async () => {
142
let entity = props.entityID;
···
154
}
155
let link = linkValue;
156
if (!linkValue.startsWith("http")) link = `https://${linkValue}`;
0
157
if (!rep) return;
158
+
159
+
// Try to get embed URL from iframely, fallback to direct URL
160
+
setLoading(true);
161
+
try {
162
+
let res = await fetch("/api/link_previews", {
163
+
headers: { "Content-Type": "application/json" },
164
+
method: "POST",
165
+
body: JSON.stringify({ url: link, type: "meta" } as LinkPreviewBody),
166
+
});
167
+
168
+
let embedUrl = link;
169
+
let embedHeight = 360;
170
+
171
+
if (res.status === 200) {
172
+
let data = await (res.json() as LinkPreviewMetadataResult);
173
+
if (data.success && data.data.links?.player?.[0]) {
174
+
let embed = data.data.links.player[0];
175
+
embedUrl = embed.href;
176
+
embedHeight = embed.media?.height || 300;
177
+
}
178
+
}
179
+
180
+
await rep.mutate.assertFact([
181
+
{
182
+
entity: entity,
183
+
attribute: "embed/url",
184
+
data: {
185
+
type: "string",
186
+
value: embedUrl,
187
+
},
188
+
},
189
+
{
190
+
entity: entity,
191
+
attribute: "embed/height",
192
+
data: {
193
+
type: "number",
194
+
value: embedHeight,
195
+
},
196
+
},
197
+
]);
198
+
} catch {
199
+
// On any error, fallback to using the URL directly
200
+
await rep.mutate.assertFact([
201
+
{
202
+
entity: entity,
203
+
attribute: "embed/url",
204
+
data: {
205
+
type: "string",
206
+
value: link,
207
+
},
208
+
},
209
+
]);
210
+
} finally {
211
+
setLoading(false);
212
+
}
213
};
214
let smoker = useSmoker();
215
···
217
<form
218
onSubmit={(e) => {
219
e.preventDefault();
220
+
if (loading) return;
221
let rect = document
222
.getElementById("embed-block-submit")
223
?.getBoundingClientRect();
···
259
<button
260
type="submit"
261
id="embed-block-submit"
262
+
disabled={loading}
263
className={`p-1 ${isSelected && !isLocked ? "text-accent-contrast" : "text-border"}`}
264
onMouseDown={(e) => {
265
e.preventDefault();
266
+
if (loading) return;
267
if (!linkValue || linkValue === "") {
268
smoker({
269
error: true,
···
283
submit();
284
}}
285
>
286
+
{loading ? <DotLoader /> : <CheckTiny />}
287
</button>
288
</div>
289
</form>