Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Commit

Permalink
add the ability for a direct image response (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
pqt committed Sep 21, 2020
1 parent 5092938 commit 4c460f1
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 36 deletions.
2 changes: 1 addition & 1 deletion data/defaultPreview.ts

Large diffs are not rendered by default.

23 changes: 15 additions & 8 deletions pages/api/github/[...repo].ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export default async (request: NextApiRequest, response: NextApiResponse): Promi
/**
* Repository owner and name
*/
const [owner, repo] = request.query.repo;
const token: string | null = (request.query.token as string) || null;
const [owner, repo, file] = request.query.repo;
const asImage = file === 'image';

/**
* Preferred colors to use
Expand All @@ -29,7 +31,7 @@ export default async (request: NextApiRequest, response: NextApiResponse): Promi
* GitHub Repository API Response
*/
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
auth: token || process.env.GITHUB_TOKEN,
});
const { data } = await octokit.repos.get({
owner,
Expand Down Expand Up @@ -94,12 +96,17 @@ export default async (request: NextApiRequest, response: NextApiResponse): Promi
)
.composite(githubLogo, 576, 190);

response.status(200).json({
data: {
id: data.id,
image: await generatedImage.getBase64Async(Jimp.MIME_PNG),
},
});
if (asImage) {
response.setHeader('Content-Type', 'image/png');
response.end(await generatedImage.getBufferAsync(Jimp.MIME_PNG));
} else {
response.status(200).json({
data: {
id: data.id,
image: await generatedImage.getBase64Async(Jimp.MIME_PNG),
},
});
}
} catch (error) {
response.status(error.status).json({
data: {
Expand Down
106 changes: 79 additions & 27 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Spinner } from '../components/loaders/Spinner';
export default (): ReactElement => {
const [owner, setOwner] = useState('pqt');
const [repo, setRepo] = useState('social-preview');
const [token, setToken] = useState('');
const [repoId, setRepoId] = useState('');
const [preview, setPreview] = useState(defaultPreview);
const [showNotification, setShowNotification] = useState(false);
Expand All @@ -23,6 +24,7 @@ export default (): ReactElement => {
const validationSchema = yup.object().shape({
owner: yup.string().required('Owner (or Organization) is required'),
repo: yup.string().required('Repository is required'),
token: yup.string(),
});

const {
Expand All @@ -38,11 +40,19 @@ export default (): ReactElement => {
const handleRepoChange = (event: ChangeEvent<HTMLInputElement>): void => {
setRepo(event.currentTarget.value);
};
const handleTokenChange = (event: ChangeEvent<HTMLInputElement>): void => {
setToken(event.currentTarget.value);
};

const onSubmit = handleSubmit(async ({ owner, repo, token }) => {
let endpoint = `/api/github/${owner}/${repo}`;

const onSubmit = handleSubmit(async ({ owner, repo }) => {
const response = await fetch(`/api/github/${owner}/${repo}`);
if (token) {
endpoint = endpoint.concat(`?token=${token}`);
}

const response = await fetch(endpoint.toString());
const { data } = await response.json();
console.log(data);

setShowNotification(false);
setNotificationMessage('');
Expand All @@ -63,7 +73,7 @@ export default (): ReactElement => {
<div className="max-w-3xl mx-auto space-y-4">
<div
className={classNames([
'relative inline-flex rounded-md shadow-sm rounded border border-gray-300 bg-gray-100 p-1 md:p-2 lg:p-3 overflow-hidden transition-opacity items-center',
'relative inline-flex shadow-sm rounded border border-gray-300 bg-gray-100 p-1 md:p-2 lg:p-3 overflow-hidden transition-opacity items-center',
isSubmitting && 'opacity-50',
])}
>
Expand Down Expand Up @@ -102,7 +112,7 @@ export default (): ReactElement => {
<div className="flex flex-col md:flex-row w-full space-y-4 md:space-x-8 md:space-y-0">
<div className="flex-1">
<label htmlFor="owner" className="block text-sm font-medium leading-5 text-gray-700">
Owner
Owner / Organization
</label>
<div className="mt-1 relative rounded-md shadow-sm">
<input
Expand All @@ -112,7 +122,7 @@ export default (): ReactElement => {
? 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-300 focus:shadow-outline-red'
: 'text-gray-700',
])}
placeholder="Owner / Org"
placeholder="pqt"
name="owner"
ref={register()}
onChange={handleOwnerChange}
Expand Down Expand Up @@ -152,7 +162,7 @@ export default (): ReactElement => {
? 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-300 focus:shadow-outline-red'
: 'text-gray-700',
])}
placeholder="Repository"
placeholder="social-preview"
name="repo"
ref={register()}
onChange={handleRepoChange}
Expand Down Expand Up @@ -181,27 +191,69 @@ export default (): ReactElement => {
</div>
</div>

<div className="space-x-4 pb-6">
<span className="inline-flex rounded-md shadow-sm">
<button
type="submit"
className="inline-flex items-center px-4 py-2 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150"
disabled={isSubmitting || !isValid}
<div className="flex space-x-8 pb-6">
<div className="flex-1 flex space-x-4">
<span className="inline-flex rounded-md shadow-sm">
<button
type="submit"
className="inline-flex items-center px-4 py-2 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150"
disabled={isSubmitting || !isValid}
>
Generate
</button>
</span>

<a
className={classNames([
'inline-flex items-center px-4 py-2 border border-transparent text-sm leading-5 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-50 focus:outline-none focus:border-indigo-300 focus:shadow-outline-indigo active:bg-indigo-200 transition transform ease-in-out duration-300',
repoId ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-4 pointer-events-none',
])}
href={preview}
download={`${owner}-${repo}.png`}
>
Generate
</button>
</span>

<a
className={classNames([
'inline-flex items-center px-4 py-2 border border-transparent text-sm leading-5 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:bg-indigo-50 focus:outline-none focus:border-indigo-300 focus:shadow-outline-indigo active:bg-indigo-200 transition transform ease-in-out duration-300',
repoId ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-4 pointer-events-none',
])}
href={preview}
download={`${owner}-${repo}.png`}
>
Download
</a>
Download
</a>
</div>

<div className="flex-1">
{/* <label htmlFor="repo" className="block text-sm font-medium leading-5 text-gray-700">
Repository
</label> */}
<div className="mt-1 relative rounded-md shadow-sm">
<input
className={classNames([
'form-input block w-full pr-10 sm:text-sm sm:leading-5',
errors?.token
? 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-300 focus:shadow-outline-red'
: 'text-gray-700',
])}
placeholder="GitHub personal access token (optional)"
name="token"
ref={register()}
onChange={handleTokenChange}
disabled={isSubmitting}
defaultValue={token}
/>

{errors?.token && (
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg className="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
clipRule="evenodd"
/>
</svg>
</div>
)}
</div>

{errors?.token && (
<p className="mt-2 text-sm text-red-600" id="email-error">
{(errors?.token as FieldError)?.message}
</p>
)}
</div>
</div>
</div>
</form>
Expand Down

1 comment on commit 4c460f1

@vercel
Copy link

@vercel vercel bot commented on 4c460f1 Sep 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.