-
-
Notifications
You must be signed in to change notification settings - Fork 14
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
11 changed files
with
239 additions
and
52 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
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,14 @@ | ||
import { OgEditor } from "../../components/OgEditor" | ||
import { INITIAL_ELEMENTS } from "../../lib/elements" | ||
|
||
interface EditorProps { | ||
params: { | ||
id: string | ||
} | ||
} | ||
|
||
export default function Editor({ params: { id } }: EditorProps) { | ||
return ( | ||
<OgEditor height={630} initialElements={INITIAL_ELEMENTS} localStorageKey={id} width={1200} /> | ||
) | ||
} |
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 |
---|---|---|
@@ -1,32 +1,101 @@ | ||
'use client' | ||
import type { MouseEvent, ReactNode } from "react"; | ||
import { Suspense, useEffect, useState } from "react"; | ||
import Link from "next/link"; | ||
import { OgEditor } from "../components/OgEditor"; | ||
import { createElementId } from "../lib/elements"; | ||
import { INITIAL_ELEMENTS, createElementId } from "../lib/elements"; | ||
import { DeleteIcon } from "../components/icons/DeleteIcon"; | ||
import { AddIcon } from "../components/icons/AddIcon"; | ||
import type { OGElement } from "../lib/types"; | ||
import { OgImage } from "../components/OgImage"; | ||
|
||
/** | ||
* The initial elements to render in the editor. | ||
* | ||
* It only contains a single element, a white background that | ||
* takes the entire width and height of the editor. | ||
*/ | ||
const initialElements: OGElement[] = [ | ||
{ | ||
id: createElementId(), | ||
tag: 'div', | ||
name: 'Box', | ||
x: 0, | ||
y: 0, | ||
width: 1200, | ||
height: 630, | ||
visible: true, | ||
rotate: 0, | ||
opacity: 100, | ||
backgroundColor: '#ffffff', | ||
}, | ||
] | ||
interface OgImageWrapperProps { | ||
href: string | ||
elements?: OGElement[] | ||
children?: ReactNode | ||
deletable?: (event: MouseEvent<HTMLSpanElement>) => void | ||
} | ||
|
||
function OgImageWrapper({ href, elements, children, deletable }: OgImageWrapperProps) { | ||
return ( | ||
<Link className="h-32 min-w-60 flex items-center justify-center text-gray-600 border rounded border-gray-200 hover:border-gray-300 relative group" href={href}> | ||
{elements ? ( | ||
<Suspense fallback={<div className="animate-pulse w-3/4 h-1/6 bg-gray-100 rounded-full" />}> | ||
<OgImage elements={elements} /> | ||
</Suspense> | ||
) : null} | ||
{children} | ||
{deletable ? ( | ||
<span className="absolute right-0 top-0 p-2 text-gray-600 hover:text-gray-900 hidden group-hover:block" onClick={deletable} role="button"> | ||
<DeleteIcon /> | ||
</span> | ||
) : null} | ||
</Link> | ||
) | ||
} | ||
|
||
interface OGImage { | ||
id: string | ||
content: OGElement[] | ||
} | ||
|
||
export default function Home() { | ||
const [ogImages, setOgImages] = useState<OGImage[]>([]) | ||
|
||
useEffect(() => { | ||
const images = Object.keys(localStorage).reduce<OGImage[]>((acc, current) => { | ||
if (current.startsWith('og-')) { | ||
acc.push({ | ||
id: current, | ||
content: JSON.parse(localStorage.getItem(current) || '[]') as OGElement[] | ||
}) | ||
} | ||
|
||
return acc | ||
}, []) | ||
|
||
setOgImages(images) | ||
}, []) | ||
|
||
function deleteOgImage(ogImage: string) { | ||
return function onClick(event: MouseEvent<HTMLSpanElement>) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
localStorage.removeItem(ogImage) | ||
setOgImages(ogImages.filter((image) => image.id !== ogImage)) | ||
} | ||
} | ||
|
||
return ( | ||
<OgEditor height={630} initialElements={initialElements} width={1200} /> | ||
<> | ||
<OgEditor height={630} initialElements={INITIAL_ELEMENTS} localStorageKey="splash" width={1200} /> | ||
<div className="w-screen h-screen bg-black/20 flex justify-center items-center absolute top-0 left-0 z-10"> | ||
<div className="p-8 rounded-md bg-white shadow-lg shadow-gray-300 max-w-3xl"> | ||
<div className="flex flex-col gap-2"> | ||
<h2 className="text-gray-800 text-xl">Templates</h2> | ||
<div className="flex gap-2 overflow-x-scroll no-scrollbar"> | ||
<OgImageWrapper elements={[]} href="/" /> | ||
<OgImageWrapper elements={[]} href="/" /> | ||
<OgImageWrapper elements={[]} href="/" /> | ||
</div> | ||
</div> | ||
<div className="h-[1px] w-full bg-gray-100 my-6" /> | ||
<div className="flex flex-col gap-2"> | ||
<h2 className="text-gray-800 text-xl">My OG images</h2> | ||
<div className="flex gap-2 overflow-x-scroll no-scrollbar"> | ||
<OgImageWrapper href={`/${createElementId()}`}> | ||
<AddIcon height="1.4em" width="1.4em" /> Start from scratch | ||
</OgImageWrapper> | ||
{ogImages.map(ogImage => { | ||
return ( | ||
<OgImageWrapper deletable={deleteOgImage(ogImage.id)} elements={ogImage.content} href={`/${ogImage.id.replace('og-', '')}`} key={ogImage.id} /> | ||
) | ||
})} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} |
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,39 @@ | ||
import usePromise from "react-promise-suspense" | ||
import { createElementStyle } from "../lib/elements" | ||
import { exportToSvg } from "../lib/export" | ||
import { loadFonts } from "../lib/fonts" | ||
import type { OGElement } from "../lib/types" | ||
|
||
async function loadOgImage(elements: OGElement[]) { | ||
const fonts = await loadFonts(elements) | ||
const reactLike = { | ||
type: 'div', | ||
props: { | ||
style: { | ||
display: 'flex', | ||
width: '100%', | ||
height: '100%', | ||
}, | ||
children: elements.map(element => ({ | ||
type: element.tag, | ||
props: { | ||
style: createElementStyle(element), | ||
...(element.tag === 'p' ? { children: element.content } : {}), | ||
}, | ||
})) | ||
} | ||
} | ||
|
||
const svg = await exportToSvg(reactLike, fonts) | ||
return `data:image/svg+xml;base64,${btoa(svg)}` | ||
} | ||
|
||
interface OgImageProps { | ||
elements: OGElement[] | ||
} | ||
|
||
export function OgImage({ elements }: OgImageProps) { | ||
const src = usePromise(loadOgImage, [elements]) | ||
|
||
return <img alt="" src={src} /> | ||
} |
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
Oops, something went wrong.