{"id":21307705,"url":"https://github.com/jdegand/image-uploader","last_synced_at":"2026-05-20T02:48:09.597Z","repository":{"id":110668603,"uuid":"480961906","full_name":"jdegand/image-uploader","owner":"jdegand","description":"DevChallenges - Legacy - Full Stack Developer - Image Uploader ","archived":false,"fork":false,"pushed_at":"2024-10-06T02:25:58.000Z","size":71,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T09:13:27.296Z","etag":null,"topics":["cloudinary","devchallenges","devchallenges-legacy","next","react-dnd"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jdegand.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-04-12T20:23:33.000Z","updated_at":"2024-10-06T02:26:02.000Z","dependencies_parsed_at":"2023-03-18T04:00:15.910Z","dependency_job_id":null,"html_url":"https://github.com/jdegand/image-uploader","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fimage-uploader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fimage-uploader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fimage-uploader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jdegand%2Fimage-uploader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jdegand","download_url":"https://codeload.github.com/jdegand/image-uploader/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243785089,"owners_count":20347409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudinary","devchallenges","devchallenges-legacy","next","react-dnd"],"created_at":"2024-11-21T16:33:43.717Z","updated_at":"2026-05-20T02:48:04.577Z","avatar_url":"https://github.com/jdegand.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eImage Uploader\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n   Solution for a challenge from  \u003ca href=\"https://web.archive.org/web/20231130051853/https://legacy.devchallenges.io/challenges/O2iGT9yBd6xZBrOcVirx\" target=\"_blank\"\u003eDevchallenges.io\u003c/a\u003e.\n\u003c/div\u003e\n\n## Table of Contents\n\n- [Overview](#overview)\n  - [Built With](#built-with)\n- [How To Use](#how-to-use)\n- [Features](#features)\n- [Requirements](#requirements)\n- [Thoughts](#thoughts)\n- [Useful Resources](#useful-resources)\n\n## Overview\n\n![Homepage](image-uploader-homepage.png)\n\n***\n\n![File Added](image-uploader-file-added.png)\n\n***\n\n![Successful Upload](image-uploader-successful-upload.png)\n\n***\n\n### Built With\n\n- [Next](https://nextjs.org)\n- [Cloudinary](https://cloudinary.com)\n- [React DND](https://react-dnd.github.io/react-dnd/about)\n\n## How To Use\n\nTo clone and run this application, you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line:\n\n```bash\n# Clone this repository\n$ git clone https://github.com/jdegand/image-uploader.git\n\n# Install dependencies\n$ npm install\n\n# Add env variables from cloudinary\n\n# Run the app\n$ npm run build\n$ npm run start\n```\n\n## Features\n\nThis application/site was created as a submission to a [DevChallenges](https://devchallenges.io/challenges) challenge. The [challenge](https://web.archive.org/web/20231130051853/https://legacy.devchallenges.io/challenges/O2iGT9yBd6xZBrOcVirx) was to build an application to complete the given user stories. **Note**: The previous design document may be incomplete, as you need to find an archived version of the challenge as all `legacy` challenges have had their documentation removed from DevChallenges.\n\n## Requirements\n\n- [x]  I can drag and drop an image to upload it\n- [x]  I can choose to select an image from my folder\n- [ ]  I can see a loader when uploading\n- [x]  When the image is uploaded, I can see the image and copy it\n- [ ]  I can choose to copy to the clipboard\n\n## Thoughts\n\n- This uses a signed signature. \n\n- You have to use NEXT_PUBLIC otherwise env variables will be undefined.\n- Make sure to build so env variables are loaded.\n\n- Next JS really helps for signing the upload as it protects your secret and saves you from coding an express server.  \n- [Cloudinary](https://github.com/cloudinary-devs/cld-signed-upload-examples) has an example where a whole express server is required.\n\n- I limited it to single file uploads - to render multiple uploads have to do extra looping when uploading \u0026 rendering the image / link. \n\n- target _blank now includes noopener by default but nextjs warns you without rel=\"noreferrer\" (which includes noopener) \n\n- need performance optimizations to lower first page load (133kb).  CSS file seems large for limited css here.  The CSS in the components may be expensive.  \n\n- You have to refresh after uploading an image.\n\n- If you upload an svg, the public cloudinary link will prompt you to download the file to see it.\n\n- if you drop an image, the button's 'no file chosen' will still display.  However, the file is saved and can be uploaded.   \n- I decided to remove it with conditional rendering.  Set title attribute of file input to uploadedFile state value? \n\n- You have to manually add a language attribute to a next js project.  [See Github](https://github.com/vercel/next.js/issues/9160) for more about this.  I find this a little bizarre and something that I guarantee users of create-next-app take for granted.\n\n## Useful Resources\n\n- [Steps to replicate a design with only HTML and CSS](https://devchallenges-blogs.web.app/how-to-replicate-design/)\n- [Dev.to](https://dev.to/es404020/file-upload-in-next-js-12i6) - file upload\n- [YouTube](https://www.youtube.com/watch?v=V8w7K1HdrFo) - Tutorial\n- [ReactGo](https://reactgo.com/nextjs-change-favicon/) - change favicon in nextjs\n- [CodeSandbox](https://codesandbox.io/s/github/react-dnd/react-dnd/tree/gh-pages/examples_js/06-other/native-files?from-embed=\u0026file=/src/TargetBox.jsx) - react dnd file drop example\n- [YouTube](https://www.youtube.com/watch?v=7lhUsK-FxYI) - Colby Fayock Image Uploader Tutorial\n- [YouTube](https://www.youtube.com/watch?v=TBOkDQEBPIU) - React DropZone Image Uploader with multiple files\n- [YouTube](https://www.youtube.com/watch?v=MAw0lQKqjRA) - React Uploader with Drag and Drop\n- [Stack Overflow](https://stackoverflow.com/questions/7752188/formdata-appendkey-value-is-not-working) - can't see what's inside FormData?\n- [W3 Schools](https://www.w3schools.com/howto/howto_js_copy_clipboard.asp) - copy to clipboard\n- [Stack Overflow](https://stackoverflow.com/questions/39501289/in-reactjs-how-to-copy-text-to-clipboard) - react copy to clipboard\n- [Github](https://github.com/cloudinary/cloudinary_js/issues/143) - 400 bad request\n- [Unicode Table](https://unicode-table.com/en/2713/) - checkmark\n- [Stack Overflow](https://stackoverflow.com/questions/50709625/link-with-target-blank-and-rel-noopener-noreferrer-still-vulnerable) - _blank\n- [Blog](https://melvingeorge.me/blog/set-html-lang-attribute-in-nextjs) - set html lang attribute in nextjs\n- [A11y Project](https://www.a11yproject.com/posts/how-to-hide-content/) - how to hide content\n- [Stack Overflow](https://stackoverflow.com/questions/5138719/change-default-text-in-input-type-file) - file input styling\n- [Stack Overflow](https://stackoverflow.com/questions/12035400/how-can-i-remove-the-no-file-chosen-tooltip-from-a-file-input-in-chrome) - title attribute of file input\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdegand%2Fimage-uploader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdegand%2Fimage-uploader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdegand%2Fimage-uploader/lists"}