forked from railwayapp/og
-
Notifications
You must be signed in to change notification settings - Fork 2
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
1 parent
8d82406
commit 20cf769
Showing
13 changed files
with
293 additions
and
27 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import tw from "twin.macro"; | ||
|
||
export const Field = tw.div` | ||
flex items-center space-x-4 | ||
`; | ||
|
||
export const Label = tw.label` | ||
w-24 | ||
`; |
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,8 @@ | ||
import React from "react"; | ||
import tw from "twin.macro"; | ||
|
||
export const Input = tw.input` | ||
appearance-none w-full border rounded | ||
px-3 py-1 h-9 | ||
focus:outline-none focus:ring-2 focus:ring-accent | ||
`; |
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,28 @@ | ||
import React from "react"; | ||
import { ILayout } from "../types"; | ||
import { Field, Label } from "./Field"; | ||
import { Input } from "./Input"; | ||
import { Select } from "./Select"; | ||
import "twin.macro"; | ||
|
||
export interface Props { | ||
layout: ILayout; | ||
} | ||
|
||
export const Layout: React.FC<Props> = ({ layout, ...props }) => { | ||
return ( | ||
<div className={`layout-${layout.name}`} tw="space-y-4"> | ||
{layout.properties.map(p => ( | ||
<Field key={p.name}> | ||
<Label>{p.name} </Label> | ||
|
||
{p.type === "text" ? ( | ||
<Input placeholder={`Value for ${p.name}`} /> | ||
) : p.type === "select" ? ( | ||
<Select options={p.options.map(value => ({ value }))} /> | ||
) : null} | ||
</Field> | ||
))} | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import classnames from "classnames"; | ||
import React from "react"; | ||
import tw from "twin.macro"; | ||
import { ChevronDown } from "react-feather"; | ||
|
||
export interface Option { | ||
value: string; | ||
text?: string; | ||
disabled?: boolean; | ||
} | ||
|
||
export interface Props { | ||
options: Option[]; | ||
value?: string; | ||
width?: string; | ||
name?: string; | ||
error?: boolean; | ||
disabled?: boolean; | ||
autoFocus?: boolean; | ||
onChange?: (value: string) => void; | ||
} | ||
|
||
export const Select = React.forwardRef<HTMLSelectElement, Props>( | ||
( | ||
{ value, options, name, error, disabled, autoFocus, onChange, ...rest }, | ||
forwardedRef, | ||
) => { | ||
return ( | ||
<div | ||
css={[ | ||
tw`relative flex items-center w-full`, | ||
disabled && tw`opacity-60`, | ||
]} | ||
> | ||
<select | ||
ref={forwardedRef} | ||
value={value} | ||
disabled={disabled} | ||
autoFocus={autoFocus} | ||
name={name} | ||
className={classnames("select", { [`select-${name}`]: name != null })} | ||
css={[ | ||
tw`bg-transparent w-full h-9 appearance-none border rounded`, | ||
tw`py-1 pl-3 pr-8`, | ||
!disabled && tw`cursor-pointer hover:border-gray-400`, | ||
error | ||
? tw`border-red-500 hover:border-red-500` | ||
: tw`border-gray-200`, | ||
tw`focus:outline-none focus-visible:ring-2 focus-visible:ring-accent`, | ||
]} | ||
{...rest} | ||
onChange={e => { | ||
if (onChange != null) { | ||
onChange(e.target.value); | ||
} | ||
}} | ||
> | ||
{options.map(opt => ( | ||
<option | ||
key={opt.value} | ||
value={opt.value} | ||
disabled={opt.disabled} | ||
tw="text-fg" | ||
> | ||
{opt.text ?? opt.value} | ||
</option> | ||
))} | ||
</select> | ||
|
||
<ChevronDown tw="h-full absolute top-0 right-2 pointer-events-none" /> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { useEffect, useState } from "react"; | ||
|
||
export const useIsMounted = (): boolean => { | ||
const [isMounted, setIsMounted] = useState(false); | ||
useEffect(() => setIsMounted(true), []); | ||
return isMounted; | ||
}; |
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,25 @@ | ||
import { ILayout } from "./types"; | ||
|
||
export const simpleLayout: ILayout = { | ||
name: "Simple", | ||
properties: [ | ||
{ name: "Test", type: "text" }, | ||
{ | ||
name: "Boop", | ||
description: "This is a test", | ||
type: "select", | ||
options: ["one", "two", "three"], | ||
}, | ||
], | ||
}; | ||
|
||
export const starterLayout: ILayout = { | ||
name: "Starter", | ||
properties: [ | ||
{ name: "Name", type: "text" }, | ||
{ name: "Icon", type: "text" }, | ||
{ name: "URL", type: "text" }, | ||
], | ||
}; | ||
|
||
export const layouts: ILayout[] = [simpleLayout, starterLayout]; |
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,36 +1,91 @@ | ||
import { NextPage } from "next"; | ||
import React from "react"; | ||
import React, { useMemo, useState } from "react"; | ||
import "twin.macro"; | ||
import { Field, Label } from "../components/Field"; | ||
import { Input } from "../components/Input"; | ||
import { Layout } from "../components/Layout"; | ||
import { Select } from "../components/Select"; | ||
import { useIsMounted } from "../hooks/useIsMounted"; | ||
import { layouts } from "../layouts"; | ||
import { useStore } from "../store"; | ||
import { FileType, Theme } from "../types"; | ||
|
||
const Home: NextPage = () => { | ||
const isMounted = useIsMounted(); | ||
|
||
return ( | ||
<main tw="px-6 max-w-6xl w-full mx-auto"> | ||
<header tw="text-center mt-20 mb-12 space-y-4"> | ||
<h1 tw="text-4xl font-bold">Railway OG Image Generator</h1> | ||
</header> | ||
|
||
<section tw="grid gap-4 grid-cols-1 md:grid-cols-3"> | ||
<Config /> | ||
<OGImage /> | ||
</section> | ||
{/* We pull the state from local storage so need the app to be loaded in the browser */} | ||
{isMounted && ( | ||
<section tw="grid gap-8 grid-cols-1 md:grid-cols-3"> | ||
<Config /> | ||
<OGImage /> | ||
</section> | ||
)} | ||
</main> | ||
); | ||
}; | ||
|
||
export default Home; | ||
|
||
export const Config: React.FC = () => { | ||
return <div tw="bg-pink-100">CONFIG</div>; | ||
const [{ theme, fileType, layout: layoutName }, setStore] = useStore(); | ||
|
||
const layout = useMemo( | ||
() => layouts.find(l => l.name === layoutName), | ||
[layoutName], | ||
); | ||
|
||
return ( | ||
<div tw="space-y-4"> | ||
<Field> | ||
<Label>Theme</Label> | ||
<Select | ||
value={theme} | ||
options={[{ value: "light" }, { value: "dark" }]} | ||
onChange={theme => setStore(s => ({ ...s, theme: theme as Theme }))} | ||
/> | ||
</Field> | ||
|
||
<Field> | ||
<Label>File type</Label> | ||
<Select | ||
value={fileType} | ||
options={[{ value: "png" }, { value: "jpeg" }]} | ||
onChange={fileType => | ||
setStore(s => ({ ...s, fileType: fileType as FileType })) | ||
} | ||
/> | ||
</Field> | ||
|
||
<Field> | ||
<Label>Layout</Label> | ||
<Select | ||
value={layoutName} | ||
options={layouts.map(l => ({ value: l.name }))} | ||
onChange={layout => setStore(s => ({ ...s, layout }))} | ||
/> | ||
</Field> | ||
|
||
<hr /> | ||
|
||
{layout == null ? ( | ||
<p>Layout {layoutName} does not exist</p> | ||
) : ( | ||
<Layout layout={layout} key={layout.name} /> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export const OGImage: React.FC = () => { | ||
return ( | ||
<div className="image-wrapper" tw="col-span-2"> | ||
<img | ||
tw="shadow-lg w-full" | ||
src="https://og-image.vercel.app/**Hello**%20World.png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fvercel-triangle-black.svg" | ||
alt="" | ||
/> | ||
<img tw="shadow-lg w-full" src="/api/boooop" alt="" /> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { createLocalStorageStateHook } from "use-local-storage-state"; | ||
import { simpleLayout } from "./layouts"; | ||
import { FileType, Theme } from "./types"; | ||
|
||
export interface StoreState { | ||
theme: Theme; | ||
fileType: FileType; | ||
layout: string; | ||
} | ||
|
||
const defaultStoreState: StoreState = { | ||
theme: "light", | ||
fileType: "png", | ||
layout: simpleLayout.name, | ||
}; | ||
|
||
export const useStore = createLocalStorageStateHook<StoreState>( | ||
"state", | ||
defaultStoreState, | ||
); |
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,32 @@ | ||
export type Theme = "light" | "dark"; | ||
export type FileType = "png" | "jpeg"; | ||
|
||
export interface IConfig { | ||
theme: Theme; | ||
fileType: FileType; | ||
} | ||
|
||
export interface ILayout { | ||
name: string; | ||
properties: LayoutProperty[]; | ||
} | ||
|
||
export type LayoutProperty = BaseLayoutProperty & | ||
( | ||
| { | ||
type: "text"; | ||
} | ||
| { | ||
type: "array"; | ||
subProperty: LayoutProperty; | ||
} | ||
| { | ||
type: "select"; | ||
options: string[]; | ||
} | ||
); | ||
|
||
export interface BaseLayoutProperty { | ||
name: string; | ||
description?: string; | ||
} |
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.