-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
381 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
apps/penxle.com/prisma/migrations/20240120121128_add_embed_model/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
-- AlterTable | ||
ALTER TABLE "users" ALTER COLUMN "role" SET DEFAULT 'USER'; | ||
|
||
-- CreateTable | ||
CREATE TABLE "embeds" ( | ||
"id" TEXT NOT NULL, | ||
"user_id" TEXT NOT NULL, | ||
"url" TEXT NOT NULL, | ||
"title" TEXT, | ||
"description" TEXT, | ||
"image_url" TEXT, | ||
"html" TEXT, | ||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
||
CONSTRAINT "embeds_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "embeds" ADD CONSTRAINT "embeds_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; |
9 changes: 9 additions & 0 deletions
9
apps/penxle.com/prisma/migrations/20240120123204_make_embed_url_unique/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
Warnings: | ||
- A unique constraint covering the columns `[url]` on the table `embeds` will be added. If there are existing duplicate values, this will fail. | ||
*/ | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "embeds_url_key" ON "embeds"("url"); |
19 changes: 19 additions & 0 deletions
19
apps/penxle.com/prisma/migrations/20240120155508_alter_embeds/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
Warnings: | ||
- You are about to drop the column `image_url` on the `embeds` table. All the data in the column will be lost. | ||
- You are about to drop the column `user_id` on the `embeds` table. All the data in the column will be lost. | ||
- The `content_filters` column on the `posts` table would be dropped and recreated. This will lead to data loss if there is data in the column. | ||
- Added the required column `site` to the `embeds` table without a default value. This is not possible if the table is not empty. | ||
- Added the required column `type` to the `embeds` table without a default value. This is not possible if the table is not empty. | ||
*/ | ||
-- DropForeignKey | ||
ALTER TABLE "embeds" DROP CONSTRAINT "embeds_user_id_fkey"; | ||
|
||
-- AlterTable | ||
ALTER TABLE "embeds" DROP COLUMN "image_url", | ||
DROP COLUMN "user_id", | ||
ADD COLUMN "site" TEXT NOT NULL, | ||
ADD COLUMN "thumbnail_url" TEXT, | ||
ADD COLUMN "type" TEXT NOT NULL; |
9 changes: 9 additions & 0 deletions
9
apps/penxle.com/prisma/migrations/20240120165507_drop_embeds_site/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
Warnings: | ||
- You are about to drop the column `site` on the `embeds` table. All the data in the column will be lost. | ||
- The `content_filters` column on the `posts` table would be dropped and recreated. This will lead to data loss if there is data in the column. | ||
*/ | ||
-- AlterTable | ||
ALTER TABLE "embeds" DROP COLUMN "site"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import got from 'got'; | ||
import { env } from '$env/dynamic/private'; | ||
|
||
export const unfurl = async (url: string) => { | ||
const resp = await got({ | ||
url: 'https://iframe.ly/api/oembed', | ||
method: 'GET', | ||
searchParams: { | ||
api_key: env.PRIVATE_IFRAMELY_API_KEY, | ||
url, | ||
omit_script: 1, | ||
}, | ||
}).json<Record<string, string>>(); | ||
|
||
if (resp.error) { | ||
throw new Error(resp.error); | ||
} | ||
|
||
return { | ||
type: resp.type, | ||
title: resp.title, | ||
description: resp.description, | ||
thumbnailUrl: resp.thumbnail_url, | ||
html: resp.html, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { iframely } from '$lib/server/external-api'; | ||
import { createId } from '$lib/utils'; | ||
import { defineSchema } from '../builder'; | ||
|
||
export const embedSchema = defineSchema((builder) => { | ||
/** | ||
* * Types | ||
*/ | ||
|
||
builder.prismaObject('Embed', { | ||
fields: (t) => ({ | ||
id: t.exposeID('id'), | ||
type: t.exposeString('type'), | ||
url: t.exposeString('url'), | ||
title: t.exposeString('title', { nullable: true }), | ||
description: t.exposeString('description', { nullable: true }), | ||
thumbnailUrl: t.exposeString('thumbnailUrl', { nullable: true }), | ||
html: t.exposeString('html', { nullable: true }), | ||
}), | ||
}); | ||
|
||
/** | ||
* * Inputs | ||
*/ | ||
|
||
const UnfurlEmbedInput = builder.inputType('UnfurlEmbedInput', { | ||
fields: (t) => ({ | ||
url: t.string(), | ||
}), | ||
}); | ||
|
||
/** | ||
* * Queries | ||
*/ | ||
|
||
// builder.queryFields((t) => ({ | ||
// })); | ||
|
||
/** | ||
* * Mutations | ||
*/ | ||
|
||
builder.mutationFields((t) => ({ | ||
unfurlEmbed: t.withAuth({ user: true }).prismaField({ | ||
type: 'Embed', | ||
nullable: true, | ||
args: { input: t.arg({ type: UnfurlEmbedInput }) }, | ||
resolve: async (query, _, { input }, { db }) => { | ||
const embed = await db.embed.findUnique({ | ||
...query, | ||
where: { url: input.url }, | ||
}); | ||
|
||
if (embed) { | ||
return embed; | ||
} | ||
|
||
try { | ||
const meta = await iframely.unfurl(input.url); | ||
|
||
return await db.embed.create({ | ||
...query, | ||
data: { | ||
id: createId(), | ||
type: meta.type, | ||
url: input.url, | ||
title: meta.title, | ||
description: meta.description, | ||
thumbnailUrl: meta.thumbnailUrl, | ||
html: meta.html, | ||
}, | ||
}); | ||
} catch { | ||
return null; | ||
} | ||
}, | ||
}), | ||
})); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
apps/penxle.com/src/lib/tiptap/node-views/embed/Component.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<script lang="ts"> | ||
import { Link } from '@penxle/ui'; | ||
import { RingSpinner } from '@penxle/ui/spinners'; | ||
import { onMount } from 'svelte'; | ||
import { graphql } from '$glitch'; | ||
import { NodeView } from '$lib/tiptap'; | ||
import type { NodeViewProps } from '$lib/tiptap'; | ||
type $$Props = NodeViewProps; | ||
$$restProps; | ||
export let node: NodeViewProps['node']; | ||
export let editor: NodeViewProps['editor'] | undefined; | ||
// export let selected: NodeViewProps['selected'] | undefined; | ||
export let deleteNode: NodeViewProps['deleteNode'] | undefined; | ||
export let getPos: NodeViewProps['getPos'] | undefined; | ||
export let updateAttributes: NodeViewProps['updateAttributes'] | undefined; | ||
const unfurlEmbed = graphql(` | ||
mutation TiptapEmbed_UnfurlEmbed_Mutation($input: UnfurlEmbedInput!) { | ||
unfurlEmbed(input: $input) { | ||
id | ||
type | ||
url | ||
title | ||
description | ||
thumbnailUrl | ||
html | ||
} | ||
} | ||
`); | ||
const unfurl = async () => { | ||
try { | ||
const resp = await unfurlEmbed({ url: node.attrs.url }); | ||
if (!resp) { | ||
throw new Error('Unfurl failed'); | ||
} | ||
updateAttributes?.({ | ||
url: resp.url, | ||
__data: resp, | ||
}); | ||
} catch { | ||
if (getPos) { | ||
editor?.commands.insertContentAt(getPos(), node.attrs.url, { updateSelection: false }); | ||
deleteNode?.(); | ||
} | ||
} | ||
}; | ||
onMount(() => { | ||
if (!node.attrs.__data) { | ||
unfurl(); | ||
} | ||
}); | ||
</script> | ||
|
||
<svelte:head> | ||
<script async src="https://cdn.iframe.ly/embed.js"></script> | ||
</svelte:head> | ||
|
||
<NodeView class="tiptap-embedded"> | ||
{#if node.attrs.__data} | ||
{#if node.attrs.__data.html} | ||
<div class="w-full"> | ||
{@html node.attrs.__data.html} | ||
</div> | ||
{:else} | ||
<Link class="border flex w-full items-center gap-4" href={node.attrs.url}> | ||
{#if node.attrs.__data.thumbnailUrl} | ||
<div class="w-100px"> | ||
<img class="aspect-1/1 object-cover" alt="" src={node.attrs.__data.thumbnailUrl} /> | ||
</div> | ||
{/if} | ||
<div class="grow p-4"> | ||
<div class="font-bold">{node.attrs.__data.title}</div> | ||
<div class="text-sm text-gray-50">{node.attrs.__data.description}</div> | ||
</div> | ||
</Link> | ||
{/if} | ||
{:else} | ||
<p class="flex gap-2 items-center text-gray-50 py-1"> | ||
{node.attrs.url} | ||
<RingSpinner class="square-4" /> | ||
</p> | ||
{/if} | ||
</NodeView> |
Oops, something went wrong.