Compare commits
No commits in common. "663bc1c6bd3b40aa80db762a4bd61aac58f42d57" and "c663372fb39ba83f5e162f33c8ae8e602c8f8935" have entirely different histories.
663bc1c6bd
...
c663372fb3
19
README.md
19
README.md
@ -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!**
|
||||||
|
@ -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
|
||||||
}
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
`
|
@ -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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
`
|
`
|
@ -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,
|
||||||
})
|
})
|
@ -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"
|
|
||||||
}
|
}
|
@ -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"
|
|
||||||
}
|
}
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user