Skip to content

Commit

Permalink
Develop (#45)
Browse files Browse the repository at this point in the history
* Some clean up, added Spotify icon for offline/loading state

* Minor clean up in Mobile view

* Updating about text.

* Fixing max width for the Tab Panel

* P-18: fixed bug when type is not track

* P-20: Add real time spotify streaming progress bar. (#21)

* P-23: Added experience section. (#24)

* P-26: Added placeholder projects section. (#27)

* Wip footer.

* develop: some footer updates, brb.

* develop: simple footer.

* P-11 (#31)

* P-11: added vitest, react testing library config for unit testing.

* P-11: add Projects unit test.

* P-11: fix bg card color.

* P-11 (#32)

* P-11: added vitest, react testing library config for unit testing.

* P-11: add Projects unit test.

* P-11: fix bg card color.

* P-11: almost done, missing Github actions and TODOS in test.

* Update src/components/Navigation/Navigation.test.tsx

* theme-mode: add dark/light mode. (#38)

* animation: add simple typing animation and set initial theme mode based on user system pref. (#41)

* cloudinary: replace png images, missing svgs (#44)
  • Loading branch information
mariatorrentedev authored Jul 4, 2024
1 parent 3d8464b commit 971e448
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 27 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ['master']
branches: ["master"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -17,28 +17,29 @@ permissions:

# Allow one concurrent deployment
concurrency:
group: 'pages'
group: "pages"
cancel-in-progress: true

jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
env:
VITE_APP_SPOTIFY_CLIENT_ID: ${{ secrets.VITE_APP_SPOTIFY_CLIENT_ID }}
VITE_APP_SPOTIFY_CLIENT_SECRET: ${{ secrets.VITE_APP_SPOTIFY_CLIENT_SECRET }}
VITE_APP_SPOTIFY_REFRESH_TOKEN: ${{ secrets.VITE_APP_SPOTIFY_REFRESH_TOKEN }}
VITE_APP_CLOUD_NAME: ${{ secrets.VITE_APP_CLOUD_NAME }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 21
cache: 'npm'
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build
Expand All @@ -52,7 +53,7 @@ jobs:
uses: actions/upload-pages-artifact@v3
with:
# Upload dist folder
path: './dist'
path: "./dist"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
57 changes: 57 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@mui/lab": "^5.0.0-alpha.170",
"axios": "^1.6.8",
"buffer": "^6.0.3",
"cloudinary-build-url": "^0.2.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-intersection-observer": "^9.8.2",
Expand Down
Binary file removed src/assets/mt-dark.png
Binary file not shown.
Binary file removed src/assets/mt-light.png
Binary file not shown.
18 changes: 18 additions & 0 deletions src/components/CloudinaryImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getCloudinaryUrl } from "../services/cloudinary";

type CloudinaryImageProps = {
publicId: string;
alt: string;
options?: Record<string, unknown>;
className?: string;
};

export default function CloudinaryImage({
publicId,
alt,
options,
className,
}: CloudinaryImageProps) {
const imageUrl = getCloudinaryUrl(publicId, options);
return <img src={imageUrl} alt={alt} className={className} />;
}
7 changes: 3 additions & 4 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as React from "react";
import { Typography, Container, Stack, IconButton } from "@mui/material";
import MTLogoDark from "../../assets/mt-dark.png";
import MTLogoLight from "../../assets/mt-light.png";
import { ThemeContext } from "../../mui/theme-context";
import { CloudinaryImage } from "../../components";

export default function Footer() {
const { theme } = React.useContext(ThemeContext);
Expand All @@ -11,8 +10,8 @@ export default function Footer() {
<Container component="footer" maxWidth="md" sx={{ padding: 2 }}>
<Stack alignItems="center" spacing={1}>
<IconButton component="a" sx={{ img: { maxWidth: 50 } }} href="#">
<img
src={theme.palette.mode === "dark" ? MTLogoDark : MTLogoLight}
<CloudinaryImage
publicId={theme.palette.mode === "dark" ? "mt-dark" : "mt-light"}
alt="Maria Torrente"
/>
</IconButton>
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { default as Experience } from "./Experience/Experience";
export { default as Projects } from "./Projects/Projects";
export { default as SpotifyNowPlaying } from "./SpotifyNowPlaying/SpotifyNowPlaying";
export { default as Footer } from "./Footer/Footer";
export { default as CloudinaryImage } from "./CloudinaryImage";
17 changes: 10 additions & 7 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export const CLIENT_ID = import.meta.env.VITE_APP_SPOTIFY_CLIENT_ID;
export const CLIENT_SECRET = import.meta.env.VITE_APP_SPOTIFY_CLIENT_SECRET;
export const REFRESH_TOKEN = import.meta.env.VITE_APP_SPOTIFY_REFRESH_TOKEN;
export const ENV = import.meta.env.VITE_APP_NODE_ENV;
export const TOKEN_ENDPOINT = "https://accounts.spotify.com/api/token";
export const NOW_PLAYING_ENDPOINT =
"https://api.spotify.com/v1/me/player/currently-playing";
export const config = {
CLIENT_ID: import.meta.env.VITE_APP_SPOTIFY_CLIENT_ID,
CLIENT_SECRET: import.meta.env.VITE_APP_SPOTIFY_CLIENT_SECRET,
REFRESH_TOKEN: import.meta.env.VITE_APP_SPOTIFY_REFRESH_TOKEN,
ENV: import.meta.env.VITE_APP_NODE_ENV,
CLOUD_NAME: import.meta.env.VITE_APP_CLOUD_NAME,
TOKEN_ENDPOINT: "https://accounts.spotify.com/api/token",
NOW_PLAYING_ENDPOINT:
"https://api.spotify.com/v1/me/player/currently-playing",
};
24 changes: 24 additions & 0 deletions src/services/cloudinary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { buildUrl } from "cloudinary-build-url";
import { config } from "../config";

type TransformationOptions = {
[key: string]: unknown;
};

export function getCloudinaryUrl(
publicId: string,
options?: TransformationOptions
): string {
if (!config.CLOUD_NAME) {
throw new Error(
"Cloudinary cloud name is required to compose the image url."
);
}

return buildUrl(publicId, {
cloud: {
cloudName: config.CLOUD_NAME,
},
transformations: options,
});
}
18 changes: 7 additions & 11 deletions src/services/spotify.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import type { NowPlayingItem } from "../types/spotify";
import axios from "axios";
import { Buffer } from "buffer";
import {
TOKEN_ENDPOINT,
NOW_PLAYING_ENDPOINT,
CLIENT_ID as clientId,
CLIENT_SECRET as clientSecret,
REFRESH_TOKEN as refreshToken,
} from "../config";
import { config } from "../config";

export type GetAccessTokenResponse = {
access_token: string;
Expand All @@ -18,17 +12,19 @@ export type GetAccessTokenResponse = {
};

export const getAccessToken = async () => {
const basic = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
const basic = Buffer.from(
`${config.CLIENT_ID}:${config.CLIENT_SECRET}`
).toString("base64");

const bodyParams = new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
refresh_token: config.REFRESH_TOKEN,
});
const body = bodyParams.toString();

try {
const response = await axios.post<GetAccessTokenResponse>(
TOKEN_ENDPOINT,
config.TOKEN_ENDPOINT,
body,
{
headers: {
Expand Down Expand Up @@ -57,7 +53,7 @@ export const getNowPlaying = async (accessToken?: string) => {
throw "No Access Token available.";
}
const response = await axios.get<GetNowPlayingResponse>(
NOW_PLAYING_ENDPOINT,
config.NOW_PLAYING_ENDPOINT,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Expand Down

0 comments on commit 971e448

Please sign in to comment.