{"id":26497579,"url":"https://github.com/dchicchon/polus","last_synced_at":"2026-04-11T10:35:22.761Z","repository":{"id":39657932,"uuid":"231015500","full_name":"dchicchon/Polus","owner":"dchicchon","description":"Plan your day using this planner! Includes daily, weekly, monthly calendars that syncs with your chrome storage. Created Using Preact + Vite","archived":false,"fork":false,"pushed_at":"2023-06-06T02:29:31.000Z","size":26715,"stargazers_count":2,"open_issues_count":18,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2023-06-28T07:44:38.528Z","etag":null,"topics":["chrome-apis","chrome-extensions","chrome-storage","cloud-tasks","firebase","firebase-auth","firebase-messaging","planner","preact","vite"],"latest_commit_sha":null,"homepage":"https://chrome.google.com/webstore/detail/planner/meajimhgfmioppbkoppphhkbcmapfngh","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dchicchon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-31T03:00:12.000Z","updated_at":"2023-06-28T05:14:31.000Z","dependencies_parsed_at":"2023-02-08T12:02:10.888Z","dependency_job_id":null,"html_url":"https://github.com/dchicchon/Polus","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchicchon%2FPolus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchicchon%2FPolus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchicchon%2FPolus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchicchon%2FPolus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dchicchon","download_url":"https://codeload.github.com/dchicchon/Polus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244620366,"owners_count":20482599,"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":["chrome-apis","chrome-extensions","chrome-storage","cloud-tasks","firebase","firebase-auth","firebase-messaging","planner","preact","vite"],"created_at":"2025-03-20T13:43:14.893Z","updated_at":"2025-12-30T20:55:15.292Z","avatar_url":"https://github.com/dchicchon.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Polus\n\nPlan your day using this planner! Includes daily, weekly, monthly calendars that syncs with your chrome storage\n\n## Photos\n\n![App Gif](https://i.imgur.com/nd4hWLg.gif)\n\n## Summary\n\nIn the past, I have found planning out my life a bit of a hassle and could never get accustomed to the act of writing in a physical daily planner (from which I never followed through with). That's why I have decided to build my own online daily planner as a google chrome extension! The way I am driven to use my planner daily now is that with each new tab I open, I am forced to look at my calendar and make plans.\n\n## Features\n\n- Three different view buttons that change accordingly: Today, Weekly, and Monthly.\n- Persistent data storage so you can view your calendar wherever you go\n\n## Table of Contents\n\n1. [Using Firebase](#firebase)\n2. [Chrome APIs](#chrome-api)\n3. [Stretch Goals](#stretch-goals)\n\n\u003chr\u003e\n\n## Desktop App Development\n\n### Running the app\n\n1. Install all the dev dependencies by running `npm i`\n2. Execute `npm run watch` to build the dist folder\n3. Load the dist folder in the `chrome://extensions` load unpacked and you should see the build!\n\n### Using Firebase \u003ca name='firebase'\u003e\u003c/a\u003e\n\nTo allow users to persist their data across their chrome browser and mobile device,\nusers can signup using `Firebase Authentication` to use the `Firestore Database` which will migrate their current data to the database.\n\nUsers will then be able to see changes realtime on their phone and on their desktop\n\nFirebase Applications\n\n- [Firebase Authentication](https://firebase.google.com/products/auth?gclid=CjwKCAjwqcKFBhAhEiwAfEr7zT2iCvpNTnta_ynLgNd8NVAW-r8Bty9p508InchOsSWtovd2jJR06RoC3YcQAvD_BwE\u0026gclsrc=aw.ds) (to allow users to sign up)\n- [Firebase Firestore](https://firebase.google.com/products/firestore?gclid=CjwKCAjwqcKFBhAhEiwAfEr7zW11fVJCzKf8sdneH8uJpXGTgLA_A0m6NKA9_CdwvfpzHZh7Dv_9WRoCvSYQAvD_BwE\u0026gclsrc=aw.ds) (to store user data)\n\nWith this case, we will be switching entirely to the `Firestore Database` so users wont be able to use the `chrome.storage.sync` data anymore. But this is\nokay! If users would like to, they can always migrate back to the `chrome.storage.sync` at no cost. Of course they can only store a certain amount of items (100kb or 500 items) in the `chrome.storage.sync` so would have to let them know if they have too much data available there. So we will allow them to delete some data first.\n\nWhen a user starts the app, it will check if they are using Firebase or not. (Of course, I will be open to switching to any other methods in the future that may be more efficient or convenient for the user). Once we have done the check, we will then grab the data from whatever they are using, `Firestore` or `chrome.storage.sync`\n\nSo\n\n1. App Starts -\u003e Check if user is loggedin\n2. If userloggedin -\u003e get firestore items\n3. not logged in -\u003e get chrome.storage.sync items\n\nCaviat -\u003e If users want to migrate their data back to `chrome.storage.sync` they must login and click `migrate` button.\n\n### Database Hierarchy\n\nEvery new user uses the default database hierarchy\n\n- How Each Entry Looks\n\n```json\n{\n  \"text\": \"Hello World\",\n  \"key\": \"12390jvc\",\n  \"color\": \"green\",\n  \"active\": true,\n};\n```\n\nHow the database is structured in chrome.storage.sync\n\n- 4/14/21: [{entryObj}, {entryObj}, {entryObj}]\n- 4/15/21: [{entryObj}, {entryObj}, {entryObj}]\n- 4/16/21: [{entryObj}, {entryObj}, {entryObj}]\n- {userData}\n\nNow, when a user decides to signup, we must migrate all their current data to the Firestore Database\nFor reference, I am using the [documentation](https://firebase.google.com/docs/firestore/data-model) for how to store my data\nI think that I will store users entries as a subcollection within userData like:\n\n- user1\n  - {user1Data}\n  - 4/14/21: [{entryObj}, {entryObj}, {entryObj}]\n  - 4/15/21: [{entryObj}, {entryObj}, {entryObj}]\n  - 4/16/21: [{entryObj}, {entryObj}, {entryObj}]\n- user2\n  - {user2Data}\n  - 5/14/21: [{entryObj}, {entryObj}, {entryObj}]\n  - 5/15/21: [{entryObj}, {entryObj}, {entryObj}]\n  - 5/16/21: [{entryObj}, {entryObj}, {entryObj}]\n- user3\n  - {user3Data}\n  - 6/14/21: [{entryObj}, {entryObj}, {entryObj}]\n  - 6/15/21: [{entryObj}, {entryObj}, {entryObj}]\n  - 6/16/21: [{entryObj}, {entryObj}, {entryObj}]\n\n```js\n// This will return all items from storage\nchrome.storage.sync.get(null, (result) =\u003e {\n  console.log(result);\n  // 1. Filter out the entries vs userdata\n  // 2. Store userData into a document\n  // 3. For each date, store it as a subcollection inside of the userData document\n  // 4. Make each date the name of the subcollection I think\n});\n```\n\n\u003chr\u003e\n\n### Using Chrome APIs \u003ca name='chrome-api'\u003e\u003c/a\u003e\n\nThere are several APIs that you can use when developing Chrome Extensions. One that I mainly use for this extension is the Chrome Storage API.\n\nUsing the Chrome Storage API, you can store items in Chrome Storage Sync that will persist your storage items in the cloud. This is how I am able to store items for each day in the calendar. Read more about this [here](https://developer.chrome.com/apps/storage)\n\n#### `Chrome Alarms`\n\nI use Chrome Alarms to change the background photo everyday at midnight and to execute `chrome notifications` at the users specified time\n\n```js\n// create an alarm\nchrome.alarms.create(\"changeBackground\", {\n      when: Date.now() + ms,\n      periodInMinutes: 60 * 24,\n    });\n\n// on alarm\nchrome.alarms.onAlarm.addListener((alarm) =\u003e {\n  if (alarm.name === \"changeBackground\") {\n    chrome.storage.sync.get(\"userSettings\", (result) =\u003e {\n      let { userSettings } = result;\n      if (userSettings.changePhoto) {\n        getPhoto();\n      }\n    });\n  }\n```\n\n#### `Chrome ContextMenu`\n\nI used this API to allow there to be items to be clicked on if the `Polus` icon was clicked in the extensions bookmark bar.\n\n```js\n// You must include these keys in order to do this! (as far as I know)\nchrome.contextMenus.create({\n  title: 'Open',\n  contexts: ['browser_action'],\n  id: 'open-sesame',\n});\n```\n\n#### `Chrome Notifications`\n\nThis API will allow you to make an notification on a users PC. I have added this in as an optional permission so the user can toggle it on or off. In order for them to execute at a desired time, I combined its use with `Chrome Alarms`\n\n```js\n// Each of the keys in notificationObj must be included to work\nlet notificationObj = {\n  message: 'Hello World',\n  type: 'basic',\n  title: 'Polus',\n  iconUrl: '/assets/polus_icon.png',\n};\nchrome.notifications.create('id', notificationObj);\n```\n\n#### `Chrome Runtime`\n\nI use this to set initial values for the Chrome Storage API for when a user first installs the extension. In this example, I set the view to \"today\" for when the user first installs.\n\n```javascript\n// runs on installed\nchrome.runtime.onInstalled.addListener(function () {\n  chrome.storage.sync.set({ view: 'today' }, function () {\n    chrome.storage.sync.get(['view'], function (result) {\n      console.log('View set to:', result.view);\n    });\n  });\n});\n\n// Sends them here if they uninstall the app\nchrome.runtime.setUninstallURL(\n  'https://docs.google.com/forms/d/1-ILvnBaztoC9R5TFyjDA_fWWbwo9WRB-s42Mqu4w9nA/edit',\n  () =\u003e {}\n);\n```\n\n[Link to Documentation](https://developer.chrome.com/extensions/runtime)\n\n#### `Chrome Identity`\n\nI use `chrome.identity` to allow the browser to give oAuth2 access for signup and signin. I need an oAuth2 token to pass to the firebase authentication\n\nIn addition to requesting it in the `permissions` in the manifest, I had to add `oauth2` in the manifest with scopes.\n\n```json\n{\n  \"oauth2\": {\n    \"client_id\": \"274422794820-42usjoqhn5sm4cfvngusc2089erhr8mh.apps.googleusercontent.com\",\n    \"scopes\": [\"https://www.googleapis.com/auth/userinfo.email\"]\n  }\n}\n```\n\n```js\nchrome.identity.getAuthToken({ interactive: true }, (token) =\u003e {\n  let credential = firebase.auth.GoogleAuthProvider.credential(null, token);\n  firebase.auth().signInWithCredential(credential);\n});\n```\n\n#### `Chrome Storage`\n\nI used Chrome Storage Sync for the extension so I would be able to sync entries with the google account so it could be used across multiple devices with the same chrome account.\n\nIt is important to note, that there is a storage limit of 100kb and 8kb limit for each item. In future builds, I will implement localStorage to help alleviate some storage weight from storage.sync.\n\nTo set chrome storage items, you must use the method\n\n```javascript\nchrome.storage.sync.set({ key: value }, function () {\n  console.log('Set Value:', value);\n});\n```\n\nHere is an example of how I used this method to add entries to a specific date in my calendar.\n\n```javascript\nchrome.storage.sync.set({ [date]: dateEntries }, function () {\n  console.log('Set Entries');\n});\n```\n\nTo get chrome storage items, you must use this method\n\n```javascript\nchrome.storage.sync.get([key], function (result) {\n  console.log(result.key);\n  // or\n  let { key } = result;\n});\n```\n\nBelow is an example of how I retrieved items from Chrome Storage to use them in my calendars. I used so that whenever a user closes the planner, they can always go back to what view they were on before they closed it.\n\n```javascript\nchrome.storage.sync.get(['view'], function (result) {\n  for (let k = 0; k \u003c viewsArr.length; k++) {\n    if (views[k].id === result['view']) {\n      views[k].setAttribute('style', 'display:flex');\n    } else {\n      views[k].setAttribute('style', 'display:none');\n    }\n  }\n});\n```\n\n[Link to Documentation](https://developer.chrome.com/extensions/storage)\n\n#### `Chrome TopSites`\n\nThis returns back an array of sites. Each site is an object that includes the url and title\n\n```javascript\nchrome.topSites.get(function (arr) {\n  console.log(arr); // list of top sites\n});\n```\n\n[Link to Documentation](https://developer.chrome.com/extensions/topSites)\n\n#### `Chrome Cookies`\n\nIt's important to set cookies for chrome extensions when using CORS (Cross Origin Resource Sharing). In this case, I used the API to set the requests pre-flight to `secure: true` and `sameSite: 'no-restriction'`.\n\n```javascript\nchrome.cookies.set(\n  {\n    url: 'https://api.unsplash.com/',\n    sameSite: 'no_restriction',\n    secure: true,\n  },\n  function (cookie) {\n    console.log('Cookie settings have been set');\n  }\n);\n```\n\n[Link to Documentation](https://developer.chrome.com/extensions/cookies)\n\n### Firebase Messaging\nI'm using [Firebase Messaging]() to send messages back and forth from the mobile app to the chrome extension. [Here's a tutorial](https://www.plasmo.com/blog/posts/firebase-cloud-messaging-chrome-extension) on how I started using messaging\n\n### Preact Signals\n\nI'm using [Preact Signals](https://preactjs.com/guide/v10/signals) to manage a global state for userSettings and drag and drop\n\n### Dragging Entries\n\n[This code sandbox](https://codesandbox.io/s/64829x0m93?file=/src/index.js) is a reference for how I was able to drag entries in and between lists.\n\n\u003chr\u003e\n\ncurl -X POST --header \"Authorization: key=AAAAP-TfikQ:APA91bGLCKk3lHzuTGWvrQ3a4i-szKMA6KbDAopVs27tMovJ7UZq1t3U7UgiBl7Z-OjzyxxeXljhOC0cB1EbPtYi7pTapool9JWBDeIa3fhHFf5FYtMdpLfWJm3AOkDEK86BvvpEqD4S” --Header \"Content-Type: application/json\" https://fcm.googleapis.com/fcm/send -d \"{\\\"to\\”:\\ \"APA91bG-Y9qaHobjdhPA0OZeEVd563NHtDd4gT25LBNJvnTpiKLB0r2KkpT_Vy9BuY1X94dfKLgTsC07xR76gV3LjqlailGZ0gHGZ9RdaDaU4k7APONLbd-X0o9LhCo-3gH9wxA0Z-TVlk4cKedLjVX7uWkIk-bdhg\"\\”,\\”notification\\\":{\\\"title\\\":\\\"Hello\\\",\\\"body\\\":\\\"Yellow\\\"}}\"\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdchicchon%2Fpolus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdchicchon%2Fpolus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdchicchon%2Fpolus/lists"}