Compare commits

..

No commits in common. "663bc1c6bd3b40aa80db762a4bd61aac58f42d57" and "c663372fb39ba83f5e162f33c8ae8e602c8f8935" have entirely different histories.

9 changed files with 68 additions and 123 deletions

View File

@ -29,13 +29,28 @@ Any contribution is welcome. If you want to test the website in your own machine
- `bun install` - Install dependencies - `bun install` - Install dependencies
- `bun dev` - Run dev server - `bun dev` - Run dev server
The development server will be available at <http://localhost:5173>. The development server will be available at http://localhost:5173.
### Environment Variables
**The LastFM feature is disabled, and this environment variable is not required yet.**
To run the project, you need to set up the following environment variables:
| Variable | Description |
|-----------------------------|--------------------------|
| `VITE_LASTFM_API_KEY` | Your [Last.fm API Key]() |
Create a `.env` file in the root of the project and add the required variables like so:
```env
VITE_LASTFM_API_KEY=your-lastfm-api-key-here
```
## Special Thanks ## Special Thanks
- [Aidan](https://github.com/ihatenodejs) - [Aidan](https://github.com/ihatenodejs)
- [lucmsilva](https://github.com/lucmsilva651/) - [lucmsilva](https://github.com/lucmsilva651/)
- NineTailedFox - NineTailedFox
- [biancarosa](https://github.com/biancarosa) - Last.fm API
**Enjoy!** **Enjoy!**

View File

@ -1,61 +1,45 @@
import { api } from "../lib/axios"; import { api } from "../lib/axios";
export interface TrackResponse { const api_key = null;
track: {
album: {
mbid: string,
"#text": string
},
artist: {
mbid: string,
"#text": string
},
date: {
uts: string,
"#text": string
},
image: [{
"#text": string,
size: string
}],
mbid: string,
name: string,
streamable: string,
url: string
}
}
export interface getRecentTracksResponse { export interface getRecentTracksResponse {
recenttracks: { recenttracks: {
track: [{ track: [
artist: { {
artist: {
mbid: string,
"#text": string
},
streamable: string,
image: [],
mbid: string, mbid: string,
"#text": string name: string,
}, url: string,
streamable: string, date: {
image: [{ uts: string,
"#text": string, "#text": string
size: string }
}],
mbid: string,
name: string,
url: string,
date: {
uts: string,
"#text": string
} }
}] ],
"@attr": {
user: string,
totalPages: string,
page: string,
perPage: string,
total: string
}
} }
} }
export async function getRecentTracks() { export async function getRecentTracks() {
try { const response = await api.get<getRecentTracksResponse>('/', {
const response = await api.get<TrackResponse>(''); params: {
console.log('Last.fm data:', response.data); api_key,
method: 'user.getrecenttracks',
return response.data; user: 'givfnz',
} catch (error) { format: 'json',
console.error('Err while fetching Last.fm data:', error); limit: 1
throw error; }
} })
return response.data
} }

View File

@ -1,13 +1,11 @@
import styled from "styled-components"; import styled from "styled-components";
{/* this is misaligned */}
export const Drawer = styled.button` export const Drawer = styled.button`
all: unset; all: unset;
color: white; color: white;
cursor: pointer; cursor: pointer;
transition: color 0.3s; transition: color 0.3s;
display: none; display: none;
font-size: 1.5rem;
&:hover { &:hover {
color: ${props => props.theme.cream} color: ${props => props.theme.cream}
@ -65,23 +63,4 @@ animation-duration: 0.5s;
&:hover { &:hover {
color: ${props => props.theme.cream} color: ${props => props.theme.cream}
} }
`
export const DrawerTitle = styled.h4`
text-align: center;
margin-top: 1rem;
color: white;
animation-name: slideIn;
animation-duration: 0.5s;
@keyframes slideIn {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
` `

View File

@ -2,7 +2,7 @@ import { HashRouter } from "react-router-dom";
import { HeaderContainer, NavLink, HomeLink, LanguageSelector } from "./styles"; import { HeaderContainer, NavLink, HomeLink, LanguageSelector } from "./styles";
import { AvatarHeader } from "../Avatar/avatar"; import { AvatarHeader } from "../Avatar/avatar";
import i18n from "../../utils/i18n"; import i18n from "../../utils/i18n";
import { Drawer, DrawerContainer, DrawerItem, DrawerTitle } from "../Drawer/styles"; import { Drawer, DrawerContainer, DrawerItem } from "../Drawer/styles";
import useDrawerVisible from "../../hooks/useDrawerVisible"; import useDrawerVisible from "../../hooks/useDrawerVisible";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -13,7 +13,6 @@ export default function Header() {
localStorage.setItem("language", event.target.value); localStorage.setItem("language", event.target.value);
}; };
const { ref, openDrawer, setOpenDrawer } = useDrawerVisible(); const { ref, openDrawer, setOpenDrawer } = useDrawerVisible();
return ( return (
<> <>
<HashRouter> <HashRouter>
@ -39,7 +38,7 @@ export default function Header() {
</HeaderContainer> </HeaderContainer>
{openDrawer && {openDrawer &&
<DrawerContainer onClick={() => setOpenDrawer(false)}> <DrawerContainer onClick={() => setOpenDrawer(false)}>
<DrawerTitle>Giv's Website</DrawerTitle> <DrawerItem>Giv's Website</DrawerItem>
<DrawerItem href="#about">{t("about")}</DrawerItem> <DrawerItem href="#about">{t("about")}</DrawerItem>
<DrawerItem href="#skills">{t("skills")}</DrawerItem> <DrawerItem href="#skills">{t("skills")}</DrawerItem>
<DrawerItem href="#contact">{t("contact")}</DrawerItem> <DrawerItem href="#contact">{t("contact")}</DrawerItem>

View File

@ -6,6 +6,6 @@ export const MainContainer = styled.div`
background-color: ${props => props.theme["gray-700"]}; background-color: ${props => props.theme["gray-700"]};
border-radius: 8px; border-radius: 8px;
@media(max-width: 640px){ @media(max-width: 640px){
margin: 0.75rem 0 3rem 0; margin: 0 0 3rem 0;
} }
` `

View File

@ -1,7 +1,5 @@
import axios from 'axios' import axios from 'axios'
const defaultApiUrl = 'https://lastfm-last-played.biancarosa.com.br/givfnz/latest-song';
export const api = axios.create({ export const api = axios.create({
baseURL: import.meta.env.VITE_LASTFM_API_URL || defaultApiUrl, baseURL: import.meta.env.VITE_LASTFM_API_URL,
}) })

View File

@ -10,10 +10,8 @@
"send": "Send", "send": "Send",
"myLast": "My Last.FM Status", "myLast": "My Last.FM Status",
"myLastDescription": "I'm listening to:", "myLastDescription": "I'm listening to:",
"lastPlayed": "Last played song:",
"lastLink": "View on Last.FM", "lastLink": "View on Last.FM",
"music": "Music", "music": "Music",
"currentlyListening": "I'm currently listening to it!", "currentlyListening": "I'm currently listening to it!",
"lastUpdate": "Last update: ", "lastUpdate": "Last update: "
"noRecentTracks": "No recent tracks found"
} }

View File

@ -10,10 +10,8 @@
"send": "Enviar", "send": "Enviar",
"myLast": "Meu status do Last.FM", "myLast": "Meu status do Last.FM",
"myLastDescription": "Dê uma olhada na música que eu estava ouvindo:", "myLastDescription": "Dê uma olhada na música que eu estava ouvindo:",
"lastPlayed": "Última música ouvida:",
"lastLink": "Clique aqui para ver a música no Last.FM", "lastLink": "Clique aqui para ver a música no Last.FM",
"music": "Música", "music": "Música",
"currentlyListening": "Eu estou ouvindo neste momento!", "currentlyListening": "Eu estou ouvindo neste momento!",
"lastUpdate": "Última atualização: ", "lastUpdate": "Última atualização: "
"noRecentTracks": "Nenhuma música recente encontrada"
} }

View File

@ -1,4 +1,4 @@
import { getRecentTracks, TrackResponse } from "../../api/lastfm"; import { getRecentTracks } from "../../api/lastfm";
import { MainContainer } from "../../components/MainContent/styles"; import { MainContainer } from "../../components/MainContent/styles";
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { Paragraph } from "../../components/Paragraph/styles"; import { Paragraph } from "../../components/Paragraph/styles";
@ -8,48 +8,22 @@ import { MusicDescription, MusicTitle } from "./styles";
export default function Music() { export default function Music() {
const { t } = useTranslation() const { t } = useTranslation()
const { data: lastResponse, isLoading, isError, error } = useQuery<TrackResponse>({ const { data: lastResponse } = useQuery({
queryKey: ['song'], queryKey: ['song'],
queryFn: getRecentTracks, queryFn: getRecentTracks
retry: 1,
refetchOnWindowFocus: false
}) })
const isAvailable = false;
const isAvailable = true; if(isAvailable){
if (isAvailable){
const track = lastResponse?.track;
const isCurrentlyPlaying = !track?.date?.["#text"];
return ( return (
<MainContainer> <MainContainer>
<MusicTitle>{t("myLast")}</MusicTitle> <MusicTitle>{t("myLast")}</MusicTitle>
<MusicDescription>{t("myLastDescription")}</MusicDescription>
{isLoading ? ( <Paragraph>{lastResponse?.recenttracks?.track[0].name} - {lastResponse?.recenttracks?.track[0].artist["#text"]}</Paragraph>
<Paragraph>Loading music data...</Paragraph> <IconLink target="blank" href={lastResponse?.recenttracks?.track[0].url}>{t("lastLink")}</IconLink>
) : isError ? ( {lastResponse?.recenttracks?.track[0]?.date?.["#text"] ?
<> <Paragraph>{t("lastUpdate")}{lastResponse?.recenttracks?.track[0]?.date["#text"]} UTC</Paragraph>
<Paragraph>Error loading music data</Paragraph> : <Paragraph>{t("currentlyListening")}</Paragraph>
<Paragraph>Error details: {error instanceof Error ? error.message : String(error)}</Paragraph> }
</>
) : (
<>
<MusicDescription>
{isCurrentlyPlaying ? t("myLastDescription") : t("lastPlayed")}
</MusicDescription>
{track ? (
<>
<Paragraph>{track.name} - {track.artist["#text"]}</Paragraph>
<IconLink target="blank" href={track.url}>{t("lastLink")}</IconLink>
{isCurrentlyPlaying ?
<Paragraph>{t("currentlyListening")}</Paragraph>
: <Paragraph>{t("lastUpdate")}{track.date?.["#text"]} UTC</Paragraph>
}
</>
) : (
<Paragraph>{t("noRecentTracks")}</Paragraph>
)}
</>
)}
</MainContainer> </MainContainer>
) )
} }