Add initial extension files for halfPage startpage

- Added icon image for the extension.
- Created manifest.json for extension configuration with permissions and new tab override.
- Implemented sidebar component with user settings for name, search engine, weather location, color scheme, and theme selection.
This commit is contained in:
wont-stream 2025-04-10 13:53:31 -04:00
parent 8de0faf8fa
commit c894c6f440
10 changed files with 166 additions and 61 deletions

View file

@ -1,72 +1,22 @@
import { useState } from 'preact/hooks';
import { ChevronLeft, ChevronRight } from 'lucide-preact';
import desc from "./desc.json";
const favicon = document.getElementById("favicon") as HTMLLinkElement;
const fetchWeather = async (lat: number, long: number) => {
const req = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${long}&current=temperature_2m,is_day,weather_code&timezone=${Intl.DateTimeFormat().resolvedOptions().timeZone}`)
const res = await req.json();
return res as {
current: {
temperature_2m: number,
is_day: number;
weather_code: number;
}
}
}
export default () => {
const [weather, setWeather] = useState<string>("Loading...");
const [imgSrc, setSrc] = useState<string>("favicon.svg");
const [wttrDesc, setWttrDesc] = useState<string>("Loading...");
const getWeather = async (coords: GeolocationCoordinates) => {
const weather = await fetchWeather(coords.latitude, coords.longitude);
const weatherCode = weather.current.weather_code;
const isDay = weather.current.is_day === 1;
const dayOrNight = isDay ? "Day" : "Night";
const weatherDesc = desc[weatherCode.toString() as keyof typeof desc][dayOrNight.toLowerCase() as "day" | "night"];
setWeather(`${weather.current.temperature_2m}°C`);
setSrc(weatherDesc.image);
favicon.href = weatherDesc.image;
setWttrDesc(`${weatherDesc.description} & ${dayOrNight}`);
}
const getAproximateLocation = async () => {
const req = await fetch("https://cf.ipv4-army.workers.dev/")
const res = await req.json();
return await getWeather(res);
}
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
const coords = position.coords;
getWeather(coords);
}, getAproximateLocation, {
enableHighAccuracy: true,
maximumAge: 30 * 60 * 1000, // 30 minutes
timeout: 5000
});
} else {
getAproximateLocation();
}
fetch(`https://wttr.in/${localStorage.getItem("location") || ""}?format=%t%20with%20%C%c&m`)
.then(res => res.text())
.then(desc => {
setWttrDesc(desc.trim());
})
return (
<>
<nav class="navbar shadow fixed-top" style="background-color: var(--bs-content-bg); border-bottom: var(--bs-border-width) solid var(--bs-content-border-color);">
<div class="container-fluid">
<div class="navbar-brand">
{wttrDesc}
<img src={imgSrc} alt="Logo" width="24" height="24" class="d-inline-block align-text-top" />
{wttrDesc}
</div>
<span class="navbar-text">
{weather}
</span>
<div class="d-flex hstack gap-2" role="search">
<button type="button" class="btn btn-outline-light btn-sm" onClick={history.back}><ChevronLeft size={20} /></button>
<button type="button" class="btn btn-outline-light btn-sm" onClick={history.forward}><ChevronRight size={20} /></button>