mirror of
https://github.com/ArthurDanjou/arthome.git
synced 2026-01-14 12:14:33 +01:00
Add weather
This commit is contained in:
@@ -59,7 +59,7 @@ function visitLink(clickType: 'self' | 'extern') {
|
|||||||
<UCard
|
<UCard
|
||||||
:ui="{
|
:ui="{
|
||||||
body: { base: 'h-full relative z-20' },
|
body: { base: 'h-full relative z-20' },
|
||||||
background: `h-full duration-300 bg-white dark:bg-gray-900 ${editMode ? '' : 'hover:bg-gray-100 dark:hover:bg-gray-800'}`,
|
background: `h-full duration-300 bg-white dark:bg-gray-900 ${editMode ? '' : 'hover:bg-zinc-100 dark:hover:bg-zinc-800'}`,
|
||||||
}"
|
}"
|
||||||
:class="editMode ? 'animate-wiggle' : 'cursor-pointer'"
|
:class="editMode ? 'animate-wiggle' : 'cursor-pointer'"
|
||||||
@click.left="visitLink('self')"
|
@click.left="visitLink('self')"
|
||||||
|
|||||||
82
app/components/App/Weather.vue
Normal file
82
app/components/App/Weather.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { WeatherType } from '~~/types/types'
|
||||||
|
|
||||||
|
const { coords, error } = useGeolocation()
|
||||||
|
|
||||||
|
const { data, status, refresh } = await useAsyncData<WeatherType>(async () => await useRequestFetch<WeatherType>()('/api/weather', {
|
||||||
|
method: 'GET',
|
||||||
|
query: {
|
||||||
|
lon: coords.value.longitude,
|
||||||
|
lat: coords.value.latitude,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
watchOnce(coords, async () => await refresh())
|
||||||
|
|
||||||
|
const getIcon = computed(() => {
|
||||||
|
if (!data.value)
|
||||||
|
return 'i-ph:cloud-fog-duotone'
|
||||||
|
switch (data.value.weather.type.toLowerCase()) {
|
||||||
|
case 'clouds':
|
||||||
|
return 'i-ph:cloud-duotone'
|
||||||
|
case 'rain':
|
||||||
|
return 'i-ph:cloud-rain-duotone'
|
||||||
|
case 'drizzle':
|
||||||
|
return 'i-ph:cloud-snow-duotone'
|
||||||
|
case 'clear':
|
||||||
|
return 'i-ph:sun-duotone'
|
||||||
|
case 'snow':
|
||||||
|
return 'i-ph:cloud-snow-duotone'
|
||||||
|
case 'thunderstorm':
|
||||||
|
return 'i-ph:cloud-lightning-duotone'
|
||||||
|
default:
|
||||||
|
return 'i-ph:cloud-fog-duotone'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ClientOnly>
|
||||||
|
<UCard
|
||||||
|
v-if="status === 'success' && !error"
|
||||||
|
class="mt-12"
|
||||||
|
:ui="{
|
||||||
|
body: { base: 'h-full relative z-20' },
|
||||||
|
background: 'h-full duration-300 bg-white dark:bg-gray-900',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="flex gap-12 items-center h-full gap-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<UBadge color="sky" class="p-2" variant="soft">
|
||||||
|
<UIcon :name="getIcon" size="32" />
|
||||||
|
</UBadge>
|
||||||
|
<p class="text-sky-400 text-xl font-medium truncate">
|
||||||
|
{{ data.weather.description.charAt(0).toUpperCase() + data.weather.description.slice(1) }} in {{ data.city.split(' ')[data.city.split(' ').length - 1] }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div class="flex gap-1">
|
||||||
|
min. <span class="text-green-400">{{ data.temp.min }}</span>°C
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1">
|
||||||
|
actual <span class="text-orange-400">{{ data.temp.feels_like }}</span> °C
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1">
|
||||||
|
max.
|
||||||
|
<span class="text-red-400">{{ data.temp.max }}</span>
|
||||||
|
°C
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<span class="text-cyan-400">{{ data.wind }}</span>
|
||||||
|
km/h
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1">
|
||||||
|
rain
|
||||||
|
<span class="text-blue-400">{{ data.temp.humidity }}</span>
|
||||||
|
%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
@@ -118,6 +118,7 @@ defineShortcuts({
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<AppWeather />
|
||||||
<div class="flex justify-end my-8 gap-4">
|
<div class="flex justify-end my-8 gap-4">
|
||||||
<UButton
|
<UButton
|
||||||
v-if="canCreateCategory()"
|
v-if="canCreateCategory()"
|
||||||
|
|||||||
@@ -85,5 +85,9 @@ export default defineNuxtConfig({
|
|||||||
url: '',
|
url: '',
|
||||||
dir: './server/db',
|
dir: './server/db',
|
||||||
},
|
},
|
||||||
|
openWeather: {
|
||||||
|
apiKey: '',
|
||||||
|
units: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,23 +1,36 @@
|
|||||||
import type { OpenWeatherType } from '~~/types/types'
|
import type { OpenWeatherType, WeatherType } from '~~/types/types'
|
||||||
|
|
||||||
export default defineCachedEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const config = useRuntimeConfig(event)
|
const config = useRuntimeConfig(event)
|
||||||
|
const { user } = await requireUserSession(event)
|
||||||
|
const query = getQuery(event)
|
||||||
|
|
||||||
|
if (Number(query.lon) === Infinity || Number(query.lat) === Infinity) {
|
||||||
|
return createError('Invalid coordinates')
|
||||||
|
}
|
||||||
|
|
||||||
const openWeather = await $fetch<OpenWeatherType>('https://api.openweathermap.org/data/2.5/weather', {
|
const openWeather = await $fetch<OpenWeatherType>('https://api.openweathermap.org/data/2.5/weather', {
|
||||||
params: {
|
params: {
|
||||||
lat: config.openWeather.lat,
|
lon: query.lon,
|
||||||
lon: config.openWeather.lon,
|
lat: query.lat,
|
||||||
appid: config.openWeather.apiKey,
|
appid: config.openWeather.apiKey,
|
||||||
lang: config.openWeather.lang,
|
lang: user.language.split('-')[0] ?? 'en',
|
||||||
units: config.openWeather.units,
|
units: config.openWeather.units,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
weather: openWeather.weather[0].description,
|
weather: {
|
||||||
|
type: openWeather.weather[0].main,
|
||||||
|
description: openWeather.weather[0].description,
|
||||||
|
},
|
||||||
city: openWeather.name,
|
city: openWeather.name,
|
||||||
temp: openWeather.main.feels_like,
|
temp: {
|
||||||
}
|
feels_like: openWeather.main.feels_like,
|
||||||
}, {
|
min: openWeather.main.temp_min,
|
||||||
maxAge: 60 * 60, // 1 hour
|
max: openWeather.main.temp_max,
|
||||||
name: 'weather',
|
humidity: openWeather.main.humidity,
|
||||||
|
},
|
||||||
|
wind: openWeather.wind.speed,
|
||||||
|
} as WeatherType
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -80,11 +80,16 @@ export const UpdateUserSchemaType = z.infer<typeof UpdateUserSchema>
|
|||||||
|
|
||||||
export interface OpenWeatherType {
|
export interface OpenWeatherType {
|
||||||
weather: Array<{
|
weather: Array<{
|
||||||
|
main: string
|
||||||
description: string
|
description: string
|
||||||
}>
|
}>
|
||||||
main: {
|
temp: {
|
||||||
feels_like: number
|
feels_like: number
|
||||||
|
temp_min: number
|
||||||
|
temp_max: number
|
||||||
|
humidity: number
|
||||||
}
|
}
|
||||||
|
wind: { speed: number }
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +99,13 @@ export interface WeatherType {
|
|||||||
type: string
|
type: string
|
||||||
description: string
|
description: string
|
||||||
}
|
}
|
||||||
temp: number
|
temp: {
|
||||||
|
feels_like: number
|
||||||
|
min: number
|
||||||
|
max: number
|
||||||
|
humidity: number
|
||||||
|
}
|
||||||
|
wind: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const locales = [
|
export const locales = [
|
||||||
|
|||||||
Reference in New Issue
Block a user