{"id":16226837,"url":"https://github.com/srmullen/svelte-firegram","last_synced_at":"2025-10-09T23:35:24.834Z","repository":{"id":145887109,"uuid":"288227178","full_name":"srmullen/svelte-firegram","owner":"srmullen","description":null,"archived":false,"fork":false,"pushed_at":"2020-08-18T14:31:48.000Z","size":38,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-08T04:05:58.494Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/srmullen.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-17T16:12:40.000Z","updated_at":"2020-08-18T14:31:50.000Z","dependencies_parsed_at":"2023-04-22T08:31:14.172Z","dependency_job_id":null,"html_url":"https://github.com/srmullen/svelte-firegram","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/srmullen/svelte-firegram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srmullen%2Fsvelte-firegram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srmullen%2Fsvelte-firegram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srmullen%2Fsvelte-firegram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srmullen%2Fsvelte-firegram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/srmullen","download_url":"https://codeload.github.com/srmullen/svelte-firegram/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srmullen%2Fsvelte-firegram/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279002310,"owners_count":26083340,"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","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-10-10T12:50:37.734Z","updated_at":"2025-10-09T23:35:24.819Z","avatar_url":"https://github.com/srmullen.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Build an Instagram Clone with Svelte and Firebase\n\nSvelte Project Setup\n--------------------\n\nFirst we need to create a new svelte project. We use the degit tool to make a copy of the sveltejs/template repo. Change into the newly created project and install the dependencies.\n\n```\nnpx degit sveltejs/template svelte-firgram\ncd svelte-firegram\nnpm install\n```\n\nNow we can start the application.\n\n`npm run dev`\n\nFirebase Setup\n--------------\n\nGo to firebase.google.com and create an account if you do not already have one.\n\nClick the 'Get Started' button and then 'Add project'. Name the project and disable analytics. When the project is ready we'll be taken to the project dashboard.\n\n# Add Firebase to your web app\n\n\u003c!-- Not sure this is needed\n\n1. Click the `\u003c/\u003e` button. Give the app a nickname and check the box to setup Firebase Hosting. Then Click 'Register app'.\n2. Copy the firebase scripts into `public/index.html` at the bottom of your body tag\n3. Install the firebase CLI for hosting\n  `npm install -g firebase-tools`\n4. Deploy to firebase hosting\n```\nfirebase login\nfirebase init\nfirebase deploy\n```\n\nAfter `firebase init` you'll be prompted to select which features you want. Choose Firestore, Functions, Hosting, Storage, and Emulators.\n\nThe CLI will ask you to choose a project. Choose the one we just setup. Get an error because I didn't set up firestore on the web console yet.\n--\u003e\n\nThe first thing we'll setup is firebase storage. This is what firebase offers for storing any types of files. We'll use it to store the images that our users will be uploading.\n\n\n## Firebase storage\n\nNavigate to the storage page on the firebase console and click 'Get started'. It will show you the default rules for the storage (all authenticated users can read/write), and let you choose the location of your storage. Choose wherever is closest to you. For now we'll allow everyone to read and write. Don't do this in production. Navigate to the rules tab under Storage and change the rules to the following.\n\n```\nrules_version = '2';\nservice firebase.storage {\n  match /b/{bucket}/o {\n    match /{allPaths=**} {\n      allow read, write;\n    }\n  }\n}\n```\n\nBack in our codebase we'll install the firbase tools.\n\n`npm install firebase`\n\nUnder `src` create a new directory called `firebase` and inside it create a `config.js` file. Import firebase app and firebase storage.\n\nOn the web console go to the project setting and find your web app. Copy the 'Config SDK snippet' and paste it into your `config.js` file.\n\n- Initialize the firebase app.\n- Initialize the storage. We'll export this so it can be used to connect to firebase storage.\n- Firebase needs to be loaded in the body of the HTML so move the index.html script tag.\n\n```javascript\nimport * as firebase from 'firebase/app';\nimport 'firebase/firebase-storage';\n\nconst firebaseConfig = {\n  apiKey: \"AIzaSyC05pHyU7BrAzw45jAkoESitbcQdA8ZoIE\",\n  authDomain: \"svelte-firegram.firebaseapp.com\",\n  databaseURL: \"https://svelte-firegram.firebaseio.com\",\n  projectId: \"svelte-firegram\",\n  storageBucket: \"svelte-firegram.appspot.com\",\n  messagingSenderId: \"839981894475\",\n  appId: \"1:839981894475:web:a9a7b24bd11f32c129f6ce\"\n};\n\nfirebase.initializeApp(firebaseConfig);\n\nconst storage = firebase.storage();\n\nexport {\n  storage\n};\n```\n\n## Firebase Firestore\n\nWhat is Firestore?\n\nSetup\n1. On the firebase web dashboard navigate to the database page and click 'Create Database'\n2. Choose 'Start in test mode'. This allows anyone to read and write to the database. It will make development easier right now, but we'll need to secure it before deploying our application.\n3. Click done to finish creating the database.\n4. In firebase/config.js import 'firebase/firebase-firestore'\n5. Initialize the firestore and export it. `const firestore = firebase.firestore();`\n6. We also want to have a timestamp on our images so we can display them in the order they were uploaded.\n\n## Firebase Hosting (Wait until after the rest of the application is developed)\n\nOn the web console navigate to the hosting page and click 'Get started'. Follow the instructions.\n\n1. Install firebase CLI\n  `npm install -g firebase-tools`\n2. Initialize the project\n  `firebase login`\n  `firebase init`\nIncomplete\n\nCode the web app.\n-----------------\n\n## UploadImage \n\nThe UploadImage component will handle sending images to firebase storage. It is a form with a file input type.\n\n- Create a components directory.\n- Add the upload button/form.\n  - Create components/UploadImage.svelte\n  - Add basic contents and import into App.svelte.\n  - Add component on the page to see that it is working.\n  - Add the html\n  - Style the html\n  - Clear out `global.css` and add in our global styles.\n   - Add visually-hidden class to`global.css`. We do this so the default file input isn't visible at all but it is still accessible to screen readers.\n   ```css\n    .visually-hidden {\n      border: 0;\n      clip: rect(0 0 0 0);\n      height: auto;\n      margin: 0;\n      overflow: hidden;\n      padding: 0;\n      position: absolute;\n      width: 1px;\n      white-space: nowrap;\n    }\n   ```\n  - Log the change events on the file input.\n  - Import storage and upload the file. Log out the percentage uploaded.\n  ```javascript\n    import { storage } from '../firebase/config';\n\n    function handleChange(event) {\n      const file = event.files[0];\n      const storageRef = storage.ref(file.name);\n      storageRef.put(file).on('state_changed', (snapshot) =\u003e {\n        const percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;\n        console.log(`${percentage}%`);\n      })\n    }\n  ```\n  - Now make sure that only images can be uploaded. Add image mime types. Try uploading an incorrect file type.\n  - add error handler\n    When something goes wrong we want to be able to tell that to the user. We'll see an error message when they choose an incorrect file type. We can also show them and error if something goes wrong during the upload, such as a loss of internet connection.\n  - add complete handler\n    Now the photos are uploading successfully. We need a way to display them. When the photo has completed uploading we'll get its storage location and save that into our firestore (aka our database).\n  - import firestore from 'config.js' and save the url and createdAt timestamp.\n  - Remove all the previously saved images since they do not have urls associated with them in the firestore.\n\n  ```javascript\n    import { projectStorage, projectFirestore, timestamp } from '../firebase/config';\n\n    async () =\u003e {\n        progress = 0;\n        uploading = false;\n        file = null;\n        const url = storageRef.getDownloadURL();\n        const createdAt = timestamp();\n        collectionRef.add({ url, createdAt });\n      }\n  ```\n\n  --- Issue ---\n  Importing firebase/storage is causing issues. Not everything about firebase seems setup at the moment. Libraries aren't loaded or aren't names as expected.\n  FIX: Import 'firebase/firebase-storage' rather than 'firebase/storage' Not sure why.\n\n## Progress Bar\n\n- Create the progress bar with full width and import it into UploadImage.\n- Add the progress property and show the progress update as an image uploads.\n- When the image is done uploading now the progress bar isn't removed. Handle that in the storage oncomplete handler.\n- Animate the progress bar by adding transition css property. Should/could this be animated with svelte?\n\n## Image Grid\n\nThe ImageGrid is used to display the images that we've uploaded to storage.\n\n- Create the ImageGrid.svelte component.\n- First just display the image you uploaded to storage. Get the url and put it in am image tag.\n```html\n  \u003cscript\u003e\n    let src = \"https://firebasestorage.googleapis.com/v0/b/svelte-firegram.appspot.com/o/IMG_0700.JPG?alt=media\u0026token=98e1316b-8f86-40fe-924b-0bd2863338cd\";\n  \u003c/script\u003e\n\n  \u003cdiv class=\"image-grid\"\u003e\n    \u003cimg {src} alt=\"Oliver\" /\u003e\n  \u003c/div\u003e\n```\n- Import the component into App.svelte and place it below the UploadImage component. You should see the image on the page.\n- Add some styles\n- Now let's load the image urls from firestore.\n- Subscribe to the firestore 'images' collection. onSnapshop assign the documents to the docs property of the component.\n- Use the #each template syntax to display the images.\n- Now upload images and they should display in the grid.\n- Now animate the images as they appear in the grid.\n  - `import { fade } from 'svelte/transition'`\n    - Add the fade directive. Give it duration so longer loading images still fade in.\n  - `import { flip } from 'svelte/animate'`\n  - flip stand for First, Last, Invert, Play. It is a strategy for optimizing the animation by precalculating the steps rather than doing them as the animation plays out.\n\n## Modal\n\n- Create `components/Modal.svelte` and import it into `App.svelte`\n```html\n\u003cscript\u003e\n  export let src;\n\u003c/script\u003e\n\n\u003cdiv class=\"modal\"\u003e\n  \u003cimg {src} alt=\"Modal\" /\u003e\n\u003c/div\u003e\n```\n- Give it a src and see that it displays the image. It doesn't look like a modal right now\n- Add styles so it looks like a modal.\n- Now display the modal on an image click.\n  - In ImageGrid create an event dispatcher.\n  - Attach on:click event to the image that dispatches an event with the image url.\n  - Im App listen to that event and set the modalSrc.\n  - View the iamge in the modal. Can't close it now.\n- Implement Modal closing on backdrop click.\n  - Dispatch a close event with backdrop on:click.\n  - Image closes no matter where on the page is clicked. Prevent that by adding the `self` modifier. i.e. `on:click|self`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrmullen%2Fsvelte-firegram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsrmullen%2Fsvelte-firegram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrmullen%2Fsvelte-firegram/lists"}