Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"zip:firefox": "export BROWSER=firefox && yarn build && node src/zip.js"
},
"dependencies": {
"colorthief": "^2.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
Binary file added public/img/weathers/01d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/01n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/02d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/02n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/03d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/03n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/04d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/04n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/09d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/09n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/10d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/10n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/11d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/11n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/13d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/13n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/50d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/weathers/50n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/background/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ chrome.runtime.onInstalled.addListener(async () => {
showsTime: true,
initialized: true,
maxBlobSize: 52_428_800, // 50MB in bytes
showsWeather: false,
weatherApiKey: null,
coords: null,
weatherUnit: 'C',
})
} catch (error) {
console.error('Failed to init data', error)
Expand Down
22 changes: 20 additions & 2 deletions src/newtab/Background.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
import { memo } from 'react'
import ColorThief from 'colorthief'
import { createRef, memo, useEffect } from 'react'
import { rgbToHex } from './utils'

const Background = ({ media, blur = 0, width, height, ...props }) => {
const colorThief = new ColorThief()

const Background = ({ media, blur = 0, width, height, onColorThief = null, ...props }) => {
const imgRef = createRef()
let style = {
filter: `blur(${(blur * 20) / 100}px)`, // max 20px
width,
height,
}

// reset color thief on video change
useEffect(() => {
if (media.blob && media.blob.type.startsWith('video')) {
onColorThief?.(null)
}
}, [media])

if (media.blob) {
const objectUrl = URL.createObjectURL(media.blob)

if (media.blob.type.startsWith('image')) {
return (
<img
ref={imgRef}
onLoad={() => {
const img = imgRef.current
const result = colorThief.getColor(img, 25)
onColorThief?.(rgbToHex(result))
}}
className="pointer-events-none object-cover w-full h-full blur-[10px]"
src={objectUrl}
style={style}
Expand Down
17 changes: 15 additions & 2 deletions src/newtab/NewTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { db, settingsStorage } from '../helper'
import '../index.css'
import Background from './Background'
import Time from './Time'
import Weather from './Weather'

export const NewTab = () => {
const [media, setMedia] = useState(null)
const [config, setConfig] = useState({})
const [dominantColor, setDominantColor] = useState(null)

function initialize() {
settingsStorage.get('mediaId').then((mediaId) => {
Expand Down Expand Up @@ -48,13 +50,24 @@ export const NewTab = () => {
return (
<div className="fixed flex flex-col flex-1 w-screen h-screen">
<div className="absolute z-[-1] w-full h-full select-none pointer-events-none">
{media && <Background media={media} blur={config.blur} />}
{media && <Background media={media} blur={config.blur} onColorThief={setDominantColor} />}
</div>
{config.showsTime && (
<div className="absolute text-6xl font-bold text-white bottom-5 right-5">
<div
className="absolute text-6xl font-bold text-white bottom-5 right-5"
style={{ color: dominantColor ?? 'black' }}
>
<Time />
</div>
)}
{config.showsWeather && (
<div
className="absolute font-bold top-5 right-5"
style={{ color: dominantColor ?? 'black' }}
>
<Weather />
</div>
)}
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/newtab/Time.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const Time = () => {

return (
<div className="flex items-center self-center justify-center p-3 rounded-lg shadow-md bg-white/50">
<h1 className="text-5xl font-bold text-center text-blue-700">{time}</h1>
<h1 className="text-center">{time}</h1>
</div>
)
}
Expand Down
89 changes: 89 additions & 0 deletions src/newtab/Weather.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useEffect, useState } from 'react'
import { showToast } from '../components/Toast'
import { settingsStorage } from '../helper'

function Weather() {
const [weather, setWeather] = useState(null)
const [coords, setCoords] = useState(null)
const [unit, setUnit] = useState('C')

useEffect(() => {
async function getCoords() {
const savedCoords = await settingsStorage.get('coords')
setCoords(savedCoords)

if (!savedCoords) {
navigator.geolocation.getCurrentPosition(
(position) => {
const newCoords = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
}
settingsStorage.set('coords', newCoords)
setCoords(newCoords)
},
(error) => {
showToast(error.message)
console.error(error)
},
)
}
}
getCoords()
}, [])

useEffect(() => {
async function getWeather() {
const appid = await settingsStorage.get('weatherApiKey')
const unit = await settingsStorage.get('weatherUnit')
setUnit(unit)

if (!appid) {
return console.warn('Please provide weather API key in settings')
}
if (coords) {
fetch(
`https://api.openweathermap.org/data/2.5/weather?${new URLSearchParams({
lat: coords.latitude,
lon: coords.longitude,
appid,
units: unit === 'C' ? 'metric' : 'imperial',
})}`,
)
.then(async (res) => {
const json = await res.json()
if (res.ok) {
setWeather(json)
} else
throw new Error(json.message ?? 'Unknown error occurred while fetching weather data.')
})
.catch((error) => {
console.error(error)
showToast(error.message)
})
}
}

getWeather()
}, [coords])

if (!weather) {
return null
}

return (
<div className="flex flex-col justify-center p-3 transition-all duration-500 ease-in-out transform rounded-lg shadow-md bg-white/50">
<p>
Temperature: {weather.main.temp}&deg;{unit}
</p>
<p>Humidity: {weather.main.humidity}%</p>
<p>Pressure: {weather.main.pressure}hPa</p>
<p className="flex flex-col items-center">
<img src={`/img/weathers/${weather.weather[0].icon}.png`} />
{weather.weather[0].description}
</p>
</div>
)
}

export default Weather
2 changes: 2 additions & 0 deletions src/newtab/index.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Toast, toastRef } from '../components/Toast'
import { NewTab } from './NewTab'
import './index.css'

ReactDOM.createRoot(document.getElementById('app')).render(
<React.StrictMode>
<NewTab />
<Toast ref={toastRef} />
</React.StrictMode>,
)
10 changes: 10 additions & 0 deletions src/newtab/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const rgbToHex = ([r, g, b]) =>
'#' +
[r, g, b]
.map((x) => {
const hex = x.toString(16)
return hex.length === 1 ? '0' + hex : hex
})
.join('')

export { rgbToHex }
54 changes: 54 additions & 0 deletions src/options/ConfigSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,29 @@ import { settingsStorage } from '../helper'

const ConfigSection = ({ onConfigChanged }) => {
const [showsTime, setshowsTime] = useState(false)
const [showsWeather, setShowsWeather] = useState(false)
const [unit, setUnit] = useState('C')
const [apiKey, setApiKey] = useState(null)
const [blurValue, setBlurValue] = useState(0)

useEffect(() => {
settingsStorage.get().then((config) => {
setshowsTime(config.showsTime ?? false)
setBlurValue(config.blur ?? 0)
setApiKey(config.weatherApiKey)
setShowsWeather(config.showsWeather ?? false)
})
}, [])

// debounce saving apiKey to storage
useEffect(() => {
const timeout = setTimeout(() => {
if (apiKey) settingsStorage.set('weatherApiKey', apiKey)
}, 500)

return () => clearTimeout(timeout)
}, [apiKey])

return (
<div className="flex flex-col gap-2">
<h2 className="mb-2 text-xl font-bold">Config</h2>
Expand All @@ -29,6 +43,46 @@ const ConfigSection = ({ onConfigChanged }) => {
}}
/>
</label>
<label htmlFor="showsWeather" className="flex items-center gap-2">
<span className="w-[100px]">Show Weather</span>
<input
type="checkbox"
id="showsWeather"
checked={showsWeather}
onChange={(e) => {
const checked = e.target.checked
setShowsWeather(checked)
settingsStorage.set('showsWeather', checked)
onConfigChanged()
}}
/>
{showsWeather && (
<div className="flex flex-row items-center ml-4 space-x-2">
<span>OpenWeatherMap API</span>
<input
placeholder="Enter your OpenWeatherMap API key here"
type="text"
className="w-[250px] text-[10px] px-2 py-1 ml-4 border-2 border-gray-300 rounded outline-none focus:border-blue-500"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
/>

<span>Unit</span>
<select
className="w-[50px] text-[10px] px-2 py-1 border-2 border-gray-300 rounded outline-none focus:border-blue-500 text-center"
value={unit}
onChange={(e) => {
setUnit(e.target.value)
settingsStorage.set('weatherUnit', e.target.value)
onConfigChanged()
}}
>
<option value="C">°C</option>
<option value="F">°F</option>
</select>
</div>
)}
</label>
<label htmlFor="blurSlider" className="flex items-center gap-2">
<span className="w-[100px]">Blur</span>
<input
Expand Down
Loading