Skip to content

Commit

Permalink
Implement extension
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitrysergienkocodefirst committed Sep 22, 2024
1 parent 3fc2432 commit 4f37670
Show file tree
Hide file tree
Showing 13 changed files with 446 additions and 93 deletions.
34 changes: 1 addition & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1 @@
This is a [Plasmo extension](https://docs.plasmo.com/) project bootstrapped with [`plasmo init`](https://www.npmjs.com/package/plasmo).

## Getting Started

First, run the development server:

```bash
pnpm dev
# or
npm run dev
```

Open your browser and load the appropriate development build. For example, if you are developing for the chrome browser, using manifest v3, use: `build/chrome-mv3-dev`.

You can start editing the popup by modifying `popup.tsx`. It should auto-update as you make changes. To add an options page, simply add a `options.tsx` file to the root of the project, with a react component default exported. Likewise to add a content page, add a `content.ts` file to the root of the project, importing some module and do some logic, then reload the extension on your browser.

For further guidance, [visit our Documentation](https://docs.plasmo.com/)

## Making production build

Run the following:

```bash
pnpm build
# or
npm run build
```

This should create a production bundle for your extension, ready to be zipped and published to the stores.

## Submit to the webstores

The easiest way to deploy your Plasmo extension is to use the built-in [bpp](https://bpp.browser.market) GitHub action. Prior to using this action however, make sure to build your extension and upload the first version to the store to establish the basic credentials. Then, simply follow [this setup instruction](https://docs.plasmo.com/framework/workflows/submit) and you should be on your way for automated submission!
Check time around the world
Binary file modified assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions components/time-block-add.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { memo, useMemo, useState, type ChangeEvent } from "react"
import { addTime, getAllTimes } from "~db"

const TimeBlockAdd = () => {
const [isAddMode, setIsAddMode] = useState<boolean>(false)
const allTimes = useMemo(() => getAllTimes(), [])
const [selectedTimeZone, setSelectedTimeZone] = useState<string>(allTimes[0].timeZone)

async function addClicked() {
const tzParts = selectedTimeZone.split('/')
setIsAddMode(false)
await addTime({
timeZone: selectedTimeZone,
place: tzParts[1]
})
}

function timeZoneChanged(event: ChangeEvent<HTMLSelectElement>): void {
setSelectedTimeZone(event.target.value)
}

return (
<div className="p-4 border-neutral border rounded flex flex-col justify-center items-center h-[88px]">
{!isAddMode &&
<div onClick={() => setIsAddMode(true)}><button type="button">+</button></div>
}
{isAddMode &&
<>
<select onChange={timeZoneChanged} className="w-full focus:outline-none">
{allTimes.map((t) => {
return <option key={t.timeZone} value={t.timeZone}>{t.place}</option>
})}
</select>
<div className="flex gap-1 mt-1">
<button className="border-neutral-100 rounded border p-1" type="button" onClick={() => {
setSelectedTimeZone(allTimes[0].timeZone)
setIsAddMode(false)
}}>Cancel</button>
<button className="border-neutral-100 rounded border p-1" type="button" onClick={addClicked}>Add</button>
</div>
</>
}
</div>
)
}

const MemoTimeBlockAdd = memo(TimeBlockAdd)

export default MemoTimeBlockAdd
30 changes: 30 additions & 0 deletions components/time-block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { deleteTime } from "~db"

type Props = {
place: string,
dateTime: Date,
timeZone: string
}

const TimeBlock = ({ place, dateTime, timeZone }: Props) => {
const dateTimeString = dateTime.toLocaleString(undefined, { timeZone: timeZone })
const dateTimeParts = dateTimeString.split(',')
const datePart = dateTimeParts[0]
const timePart = dateTimeParts[1].trimStart()

async function deleteClicked(): Promise<void> {
debugger
await deleteTime(place)
}

return (
<div className="p-4 border-neutral border rounded flex flex-col justify-center items-center relative">
<button className="absolute top-1 right-1 leading-[0]" type="button" onClick={deleteClicked}>-</button>
<div>{place}</div>
<div>{datePart}</div>
<div>{timePart}</div>
</div>
)
}

export default TimeBlock
1 change: 1 addition & 0 deletions constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const TIMES_STORAGE_KEY = 'times-storage-key'
53 changes: 53 additions & 0 deletions db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { Time } from "~types"
import { Storage } from "@plasmohq/storage"
import { TIMES_STORAGE_KEY } from "~constants"

const defaultTimes: Array<Time> = [
{ place: 'London', timeZone: 'Europe/London' },
{ place: 'Moscow', timeZone: 'Europe/Moscow' },
{ place: 'New York', timeZone: 'America/New_York' },
{ place: 'Tokyo', timeZone: 'Asia/Tokyo' }
]

export const getTimes = async () => {
const storage = new Storage()

const times = await storage.get<Array<Time>>(TIMES_STORAGE_KEY)
if (times == undefined) {
await storage.set(TIMES_STORAGE_KEY, defaultTimes)
return defaultTimes
}

return times
}

export const getAllTimes: () => Array<Time> = () => {
const timeZones = Intl.supportedValuesOf('timeZone');
const times: Array<Time> = timeZones.map((tz) => {
const tzParts = tz.split('/')
return {
place: tzParts[1],
timeZone: tz
}
})

return times
}

export const addTime = async (time: Time) => {
const storage = new Storage()

const times = await storage.get<Array<Time>>(TIMES_STORAGE_KEY)
times.push(time)
await storage.set(TIMES_STORAGE_KEY, times)
}

export const deleteTime = async (place: string) => {
const storage = new Storage()

const times = await storage.get<Array<Time>>(TIMES_STORAGE_KEY)
const updatedTimes = times.filter((time) => {
return time.place != place
});
await storage.set(TIMES_STORAGE_KEY, updatedTimes)
}
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@
"package": "plasmo package"
},
"dependencies": {
"@plasmohq/storage": "^1.12.0",
"plasmo": "0.89.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "4.1.1",
"@types/chrome": "0.0.258",
"@types/node": "20.11.5",
"@types/react": "18.2.48",
"@types/react-dom": "18.2.18",
"@types/react": "18.3.5",
"@types/react-dom": "18.3.0",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"prettier": "3.2.4",
"tailwindcss": "^3.4.11",
"typescript": "5.3.3"
},
"manifest": {
"host_permissions": [
"https://*/*"
]
}
}
67 changes: 48 additions & 19 deletions popup.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,55 @@
import { useState } from "react"
import 'style.css'
import { useEffect, useRef, useState } from 'react'
import { getTimes } from '~db'
import TimeBlock from '~components/time-block'
import type { Time } from '~types'
import TimeBlockAdd from '~components/time-block-add'
import { Storage } from '@plasmohq/storage'
import { TIMES_STORAGE_KEY } from '~constants'

function IndexPopup() {
const [data, setData] = useState("")
function Popup() {
const [times, setTimes] = useState<Array<Time>>([])
const [currentDateTime, setCurrentDateTime] = useState<Date>(new Date())
const interval = useRef<NodeJS.Timeout>()
const storage = new Storage()

const updateTimes = async () => {
const times = await getTimes()
setTimes(times)
}

useEffect(() => {
interval.current = setInterval(() => {
setCurrentDateTime(new Date())
}, 1000)
updateTimes()
storage.watch({
[TIMES_STORAGE_KEY]: (n) => {
setTimes(n.newValue)
}
})

return () => {
clearInterval(interval.current)
storage.unwatchAll()
}
}, [])

const timeBlocks = times.map((time) => {
return <TimeBlock key={time.place} place={time.place} timeZone={time.timeZone} dateTime={currentDateTime} />
})

return (
<div
style={{
padding: 16
}}>
<h2>
Welcome to your{" "}
<a href="https://www.plasmo.com" target="_blank">
Plasmo
</a>{" "}
Extension!
</h2>
<input onChange={(e) => setData(e.target.value)} value={data} />
<a href="https://docs.plasmo.com" target="_blank">
View Docs
</a>
<div className="grid grid-cols-3 gap-4 p-4">
{times.length == 0 && <div>Loading...</div>}
{times.length > 0 &&
<>
{timeBlocks}
<TimeBlockAdd />
</>
}
</div>
)
}

export default IndexPopup
export default Popup
9 changes: 9 additions & 0 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @type {import('postcss').ProcessOptions}
*/
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}
9 changes: 9 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base{
body {
width: 400px;
}
}
10 changes: 10 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
mode: "jit",
darkMode: "class",
content: [
"./**/*.tsx",
"!./**/node_modules/**/*.{html,js,ts,tsx,jsx}"
],
plugins: []
}
4 changes: 4 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type Time = {
place: string,
timeZone: string
}
Loading

0 comments on commit 4f37670

Please sign in to comment.