From cc1cd9610f2c06795530587c1541cadb249da43b Mon Sep 17 00:00:00 2001 From: Bartek Paczesny Date: Mon, 8 Jan 2024 23:08:40 +0100 Subject: [PATCH] Update configuration and widget layout --- .gitignore | 1 + README.md | 60 ++++++--- components/articles/widget.tsx | 2 +- .../atlassian/hall-of-fame/progress-bar.tsx | 2 +- components/clock/widget.tsx | 22 +++ components/home.tsx | 10 +- components/spotify/widget.tsx | 18 +-- components/ui/card.tsx | 125 +++++++++--------- components/weather/widget.tsx | 85 ++++++++++++ hooks/use-forecast.ts | 29 ++++ next.config.js | 4 + package.json | 4 +- tailwind.config.js | 4 +- types/forecast.ts | 61 +++++++++ 14 files changed, 326 insertions(+), 101 deletions(-) create mode 100644 components/clock/widget.tsx create mode 100644 components/weather/widget.tsx create mode 100644 hooks/use-forecast.ts create mode 100644 types/forecast.ts diff --git a/.gitignore b/.gitignore index 28a38e3..798e636 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # local env files .env*.local +.env # vercel .vercel diff --git a/README.md b/README.md index c403366..919b30b 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,52 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +# New Tab Extension (chromium) + +## Description + +This project is a new tab extension that enhances the functionality of your browser's new tab page. It allows you to customize the appearance and add useful features to make your browsing experience more productive. ## Getting Started -First, run the development server: +To get started with this project, follow the steps below: + +### Prerequisites + +- [Node.js](https://nodejs.org) installed on your machine. +- [pnpm](https://pnpm.io) installed on your machine. + +### Installation + +1. Clone the repository: + + ```bash + git clone https://github.com/your-username/newtab-extension.git + ``` + +2. Navigate to the project directory: -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` + ```bash + cd newtab-extension + ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +3. Install the dependencies: -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + ```bash + pnpm install + ``` -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. +### Usage -## Learn More +1. Load the extension in your browser: -To learn more about Next.js, take a look at the following resources: + - Open your browser and go to the extensions page. + - Enable the developer mode. + - Click on "Load unpacked" and select the `dist` directory in the project. -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +2. Enjoy the enhanced new tab experience! -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! +## Contributing -## Deploy on Vercel +Contributions are welcome! If you have any ideas, suggestions, or bug reports, please open an issue or submit a pull request. -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +## License -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +This project is licensed under the [MIT License](LICENSE). diff --git a/components/articles/widget.tsx b/components/articles/widget.tsx index 16b1d99..75655c3 100644 --- a/components/articles/widget.tsx +++ b/components/articles/widget.tsx @@ -19,7 +19,7 @@ function ArticlesWidget({ articles }: Props) { }, [articles]); return ( - +

Most Recent Articles

{mostRecentArticles.map((article) => ( diff --git a/components/atlassian/hall-of-fame/progress-bar.tsx b/components/atlassian/hall-of-fame/progress-bar.tsx index cd993a3..8e92470 100644 --- a/components/atlassian/hall-of-fame/progress-bar.tsx +++ b/components/atlassian/hall-of-fame/progress-bar.tsx @@ -17,7 +17,7 @@ function ProgressBar({ progress, name, color }: Props) { "h-2 rounded-full", `bg-gradient-to-r from-${ color.split("-")[0] - }-600 to-${color.split("-")[0]}-400` + }-600 to-${color.split("-")[0]}-500` )} style={{ width: `${progress}%` }} > diff --git a/components/clock/widget.tsx b/components/clock/widget.tsx new file mode 100644 index 0000000..23cae35 --- /dev/null +++ b/components/clock/widget.tsx @@ -0,0 +1,22 @@ +import { Card, CardContent } from "@/components/ui/card"; + +type Props = {}; + +function ClockWidget({}: Props) { + return ( + + +
+
+ 12:00 +
+
+ Monday, 1st January +
+
+
+
+ ); +} + +export default ClockWidget; diff --git a/components/home.tsx b/components/home.tsx index 63afb92..dcfbf0c 100644 --- a/components/home.tsx +++ b/components/home.tsx @@ -1,15 +1,19 @@ import ArticlesWidget from "@/components/articles/widget"; import useArticles from "@/hooks/use-articles"; -import SpotifyWidget from "./spotify/widget"; +import SpotifyWidget from "@/components/spotify/widget"; +import WeatherWidget from "@/components/weather/widget"; +import ClockWidget from "@/components/clock/widget"; type Props = {}; function Home({}: Props) { const { articles, loading } = useArticles(); return ( -
- +
+ {!loading && } + +
); } diff --git a/components/spotify/widget.tsx b/components/spotify/widget.tsx index 14806b6..76575ec 100644 --- a/components/spotify/widget.tsx +++ b/components/spotify/widget.tsx @@ -13,20 +13,16 @@ type Props = {}; function SpotifyWidget({}: Props) { return ( - +
Album cover
@@ -34,23 +30,23 @@ function SpotifyWidget({}: Props) { Daily Mix - + 12 Tracks
-
-
+
+
-
+
1:23 diff --git a/components/ui/card.tsx b/components/ui/card.tsx index afa13ec..f8ea7bd 100644 --- a/components/ui/card.tsx +++ b/components/ui/card.tsx @@ -1,79 +1,86 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes + HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" +
+)); +Card.displayName = "Card"; const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes + HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" +
+)); +CardHeader.displayName = "CardHeader"; const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLParagraphElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -

-)) -CardTitle.displayName = "CardTitle" +

+)); +CardTitle.displayName = "CardTitle"; const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLParagraphElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -

-)) -CardDescription.displayName = "CardDescription" +

+)); +CardDescription.displayName = "CardDescription"; const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes + HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -

-)) -CardContent.displayName = "CardContent" +
+)); +CardContent.displayName = "CardContent"; const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes + HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" +
+)); +CardFooter.displayName = "CardFooter"; -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/components/weather/widget.tsx b/components/weather/widget.tsx new file mode 100644 index 0000000..cd4b2f0 --- /dev/null +++ b/components/weather/widget.tsx @@ -0,0 +1,85 @@ +import { Card, CardContent } from "@/components/ui/card"; +import useForecast from "@/hooks/use-forecast"; +import { GaugeCircle, Thermometer, Wind } from "lucide-react"; + +type Props = {}; + +function WeatherWidget({}: Props) { + const { forecast, loading } = useForecast(); + + if (loading && !forecast) return null; + + // Icon url + // https://openweathermap.org/img/wn/10d@2x.png + + return ( + forecast && ( + + +
+

+ {forecast.name} +

+

+ {new Date().toLocaleDateString("en-PL", { + weekday: "long", + month: "long", + day: "numeric", + })} +

+
+
+

+ {Math.round(forecast.main.temp)}° +

+

+ {forecast.weather && + forecast.weather.length > 0 && + forecast.weather[0].description[0].toUpperCase() + + forecast.weather[0].description.slice(1)} +

+
+
+
+
+
+ +

+ {forecast.wind.speed} m/s +

+

+ Wind +

+
+
+
+
+ +

+ {forecast.main.humidity}% +

+

+ Humidity +

+
+
+
+
+ +

+ {forecast.main.pressure}hPa +

+

+ Pressure +

+
+
+
+
+
+
+ ) + ); +} + +export default WeatherWidget; diff --git a/hooks/use-forecast.ts b/hooks/use-forecast.ts new file mode 100644 index 0000000..7bb11bf --- /dev/null +++ b/hooks/use-forecast.ts @@ -0,0 +1,29 @@ +import { Forecast } from "@/types/forecast"; +import { useEffect, useState } from "react"; +import getConfig from "next/config"; + +const { OpenWeatherApiKey } = getConfig().publicRuntimeConfig; + +const useForecast = () => { + const [forecast, setForecast] = useState(); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const getForecast = async () => { + setLoading(true); + navigator.geolocation.getCurrentPosition(async (position) => { + const res = await fetch( + `https://api.openweathermap.org/data/2.5/weather?lat=${position.coords.latitude}&lon=${position.coords.longitude}&units=metric&&appid=${OpenWeatherApiKey}` + ); + const data = (await res.json()) as Forecast; + setForecast(data); + setLoading(false); + }); + }; + getForecast(); + }, []); + + return { forecast, loading }; +}; + +export default useForecast; diff --git a/next.config.js b/next.config.js index a515944..c69903c 100644 --- a/next.config.js +++ b/next.config.js @@ -4,6 +4,10 @@ const nextConfig = { unoptimized: true, }, output: "export", + publicRuntimeConfig: { + // Will be available on both server and client + OpenWeatherApiKey: process.env.OPENWEATHER_APIKEY, + }, }; module.exports = nextConfig; diff --git a/package.json b/package.json index 47826d0..dfaa166 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,7 @@ "build": "next build", "start": "next start", "lint": "next lint", - "copy-out": "mv out/_next out/next && rsync -va --delete-after out/next/ ./extension/next/ && rm -rf out", - "copy-public": "cp public/images/* extension/images", - "export": "next build && npm run copy-out" + "export": "cp -r out/_next out/next && cp -r out/* extension && sed -i 's/_next/next/g' extension/index.html && rm -r out && rm -r extension/_next" }, "dependencies": { "@radix-ui/react-checkbox": "^1.0.4", diff --git a/tailwind.config.js b/tailwind.config.js index 5b24e93..4b52c06 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -9,7 +9,9 @@ module.exports = { ], safelist: [ { - pattern: /(from|to)-+/, // 👈 This includes bg of all colors and shades + // pattern: /(from|to)-+/, // 👈 This includes bg of all colors and shades + // only for from and bg blue, red, green + pattern: /(from|to)-(blue|yellow|green)-(600|500|400)/, }, ], prefix: "", diff --git a/types/forecast.ts b/types/forecast.ts new file mode 100644 index 0000000..5e06399 --- /dev/null +++ b/types/forecast.ts @@ -0,0 +1,61 @@ +export interface Forecast { + coord: Coord; + weather: Weather[]; + base: string; + main: Main; + visibility: number; + wind: Wind; + rain: Rain; + clouds: Clouds; + dt: number; + sys: Sys; + timezone: number; + id: number; + name: string; + cod: number; +} + +export interface Clouds { + all: number; +} + +export interface Coord { + lon: number; + lat: number; +} + +export interface Main { + temp: number; + feels_like: number; + temp_min: number; + temp_max: number; + pressure: number; + humidity: number; + sea_level: number; + grnd_level: number; +} + +export interface Rain { + "1h": number; +} + +export interface Sys { + type: number; + id: number; + country: string; + sunrise: number; + sunset: number; +} + +export interface Weather { + id: number; + main: string; + description: string; + icon: string; +} + +export interface Wind { + speed: number; + deg: number; + gust: number; +}