Skip to content

Commit

Permalink
mobile responsive design has updated
Browse files Browse the repository at this point in the history
  • Loading branch information
ElvinWeb committed Jul 3, 2024
1 parent d29d51c commit fd5f1f4
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 113 deletions.
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/>
<link rel="stylesheet" href="./src/sass/main.scss" />
<script defer src="./src/js/controller.js" type="module"></script>
<title>Forkify // Where Culinary Delights Await Your Fork</title>
<title>Forkify ~ Where culinary delights await your fork</title>
</head>

<body>
Expand Down Expand Up @@ -311,8 +311,8 @@ <h3 class="upload__heading">Recipe data</h3>
<input value="" required name="publisher" type="text" />
<label>Prep time</label>
<input value="" required name="cookingTime" type="number" />
<label>Servings</label>
<input value="" required name="servings" type="number" />
<!-- <label>Servings</label>
<input value="" required name="servings" type="number" /> -->
</div>

<div class="upload__column">
Expand Down
19 changes: 16 additions & 3 deletions src/js/config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
const API_URL = "https://forkify-api.herokuapp.com/api/v2/recipes";
const API_KEY = "a3a17dd3-d5ba-4a69-b796-e2ac3fa11dcb";
const SPOONACULAR_API_URL = `https://api.spoonacular.com/recipes/parseIngredients`;
const SPOONACULAR_API_KEY = "622843b5344a4effbf4516c17ed810f3";
// const SPOONACULAR_API_URL = `https://api.spoonacular.com/recipes/parseIngredients`;
// const SPOONACULAR_API_KEY = "622843b5344a4effbf4516c17ed810f3";
const TIMEOUT_SEC = 10;
const RES_PER_PAGE = 15;
const MODAL_CLOSE_SEC = 2;

const SERVINGS_TO_UPLOAD = 4;
const FORBIDDEN_PATTERN = /[\d,;!@#$%^&*()_+\=\[\]{}|\\:";'<>?,./]/;
const API_URLS = {
recipes(id) {
return `${API_URL}/${id}?key=${API_KEY}`;
},
search(searchValue) {
return `${API_URL}?search=${searchValue}&key=${API_KEY}`;
},
data: `${API_URL}?key=${API_KEY}`,
};
export {
API_KEY,
SPOONACULAR_API_URL,
Expand All @@ -14,4 +24,7 @@ export {
RES_PER_PAGE,
MODAL_CLOSE_SEC,
API_URL,
API_URLS,
FORBIDDEN_PATTERN,
SERVINGS_TO_UPLOAD,
};
7 changes: 6 additions & 1 deletion src/js/controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as model from "./model.js";
import { MODAL_CLOSE_SEC } from "./config.js";
import { MODAL_CLOSE_SEC, FORBIDDEN_PATTERN } from "./config.js";
import recipeView from "./views/recipeView.js";
import searchView from "./views/searchView.js";
import resultsView from "./views/resultsView.js";
Expand Down Expand Up @@ -30,6 +30,11 @@ const controlSearchResults = async function () {
try {
resultsView.renderSpinner();
const query = searchView.getQuery();
const patternMatch = FORBIDDEN_PATTERN.test(query);
if (patternMatch) {
resultsView.renderError("You searched query is not allowed!");
return;
}

await model.loadSearchResults(query);
resultsView.render(model.getSearchResultsPage());
Expand Down
41 changes: 37 additions & 4 deletions src/js/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ export const AJAX = async function (
headers: {
"Content-Type": contentType,
},
body: contentType === "application/json"
? JSON.stringify(uploadData)
: new URLSearchParams(uploadData),
body:
contentType === "application/json"
? JSON.stringify(uploadData)
: new URLSearchParams(uploadData),
})
: fetch(url);

const res = await Promise.race([fetchPro, timeout(TIMEOUT_SEC)]);
const data = await res.json();

if (!res.ok) throw new Error(`${data.message} (${res.status})`);

return data;
} catch (err) {
throw err;
Expand All @@ -44,3 +45,35 @@ export const getTotalNutrientAmount = function (ingredientsArr, nutrient) {
)
.reduce((acc, ingNutr) => acc + ingNutr, 0);
};
export const formatIngredientsArr = function (newRecipe) {
const ingredientsDataArr = Object.entries(newRecipe)
.filter((entry) => entry[0].startsWith("ingredient"))
.map((ingData) => {
const ingIndex = +ingData[0].split("-").slice(-2, -1) - 1;
const [ingType] = ingData[0].split("-").slice(-1);
const ingValue = ingData[1];
return [ingIndex, ingType, ingValue];
});
const ingQuantity = ingredientsDataArr.filter(
(curr) => curr[1] === "quantity"
);
const ingUnit = ingredientsDataArr.filter((curr) => curr[1] === "unit");
const ingDescription = ingredientsDataArr.filter(
(curr) => curr[1] === "description"
);
const ingredients = [];
for (let i = 0; i < 8; i++) {
if (
ingQuantity[i][2] === "" &&
ingUnit[i][2] === "" &&
ingDescription[i][2] === ""
)
break;
ingredients.push({
quantity: ingQuantity[i][2] ? +ingQuantity[i][2] : null,
unit: ingUnit[i][2],
description: ingDescription[i][2],
});
}
return ingredients;
};
96 changes: 49 additions & 47 deletions src/js/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import {
API_URL,
RES_PER_PAGE,
API_KEY,
API_URLS,
BASE_API_URL,
SPOONACULAR_API_KEY,
SPOONACULAR_API_URL,
SERVINGS_TO_UPLOAD,
} from "./config.js";
import { AJAX, getTotalNutrientAmount } from "./helpers.js";
import {
AJAX,
formatIngredientsArr,
getTotalNutrientAmount,
} from "./helpers.js";

export const state = {
recipe: {},
Expand Down Expand Up @@ -37,7 +43,7 @@ const createRecipeObject = function (data) {

export const loadRecipe = async function (id) {
try {
const data = await AJAX(`${API_URL}/${id}?key=${API_KEY}`);
const data = await AJAX(API_URLS.recipes(id));
state.recipe = createRecipeObject(data);

if (state.bookmarks.some((bookmark) => bookmark.id === id)) {
Expand All @@ -46,41 +52,40 @@ export const loadRecipe = async function (id) {
state.recipe.bookmarked = false;
}

const ingredientList = state.recipe.ingredients
.map(
(ing) => `${ing.quantity ?? ""} ${ing.unit ?? ""} ${ing.description}`
)
.join("\n");

const ingredientsData = await AJAX(
`${SPOONACULAR_API_URL}?apiKey=${SPOONACULAR_API_KEY}`,
{
ingredientList: ingredientList,
servings: state.recipe.servings,
includeNutrition: true,
},
"application/x-www-form-urlencoded"
);

const calories = getTotalNutrientAmount(ingredientsData, "calories");
const carbs = getTotalNutrientAmount(ingredientsData, "carbohydrates");
const proteins = getTotalNutrientAmount(ingredientsData, "protein");
const fats = getTotalNutrientAmount(ingredientsData, "fat");

state.recipe.calories = Math.floor(calories / state.recipe.servings);
state.recipe.carbs = Math.floor(carbs / state.recipe.servings);
state.recipe.proteins = Math.floor(proteins / state.recipe.servings);
state.recipe.fats = Math.floor(fats / state.recipe.servings);
// const ingredientList = state.recipe.ingredients
// .map(
// (ing) => `${ing.quantity ?? ""} ${ing.unit ?? ""} ${ing.description}`
// )
// .join("\n");

// const ingredientsData = await AJAX(
// `${SPOONACULAR_API_URL}?apiKey=${SPOONACULAR_API_KEY}`,
// {
// ingredientList: ingredientList,
// servings: state.recipe.servings,
// includeNutrition: true,
// },
// "application/x-www-form-urlencoded"
// );

// const calories = getTotalNutrientAmount(ingredientsData, "calories");
// const carbs = getTotalNutrientAmount(ingredientsData, "carbohydrates");
// const proteins = getTotalNutrientAmount(ingredientsData, "protein");
// const fats = getTotalNutrientAmount(ingredientsData, "fat");

// state.recipe.calories = Math.floor(calories / state.recipe.servings);
// state.recipe.carbs = Math.floor(carbs / state.recipe.servings);
// state.recipe.proteins = Math.floor(proteins / state.recipe.servings);
// state.recipe.fats = Math.floor(fats / state.recipe.servings);
} catch (err) {
console.log(err);
throw err;
}
};

export const loadSearchResults = async function (query) {
try {
state.search.query = query;
const data = await AJAX(`${API_URL}?search=${query}&key=${API_KEY}`);
const data = await AJAX(API_URLS.search(query));
console.log(data);

const { recipes } = data.data;
Expand Down Expand Up @@ -119,8 +124,6 @@ export const updateServings = function (newServings) {
export const filterIngredients = function () {
state.recipe.ingredients.reduce((acc, cur) => acc + cur, 0);
};
export const filterMinutes = function () {};

const persistBookmarks = function () {
localStorage.setItem("bookmarks", JSON.stringify(state.bookmarks));
};
Expand All @@ -143,35 +146,34 @@ const init = function () {
if (storage) state.bookmarks = JSON.parse(storage);
};

init();

export const uploadRecipe = async function (newRecipe) {
try {
const ingredients = Object.entries(newRecipe)
.filter((entry) => entry[0].startsWith("ingredient") && entry[1] !== "")
.map((ingredient) => {
const ingredientArr = ingredient[1].split(",").map((ing) => ing.trim());
if (ingredientArr.length !== 3) {
throw new Error("Invalid ingredient format");
}
const [quantity, unit, description] = ingredientArr;
return { quantity: quantity ? +quantity : null, unit, description };
});

// const ingredients = Object.entries(newRecipe)
// .filter((entry) => entry[0].startsWith("ingredient") && entry[1] !== "")
// .map((ingredient) => {
// const ingredientArr = ingredient[1].split(",").map((ing) => ing.trim());
// if (ingredientArr.length !== 3) {
// throw new Error("Invalid ingredient format");
// }
// const [quantity, unit, description] = ingredientArr;
// return { quantity: quantity ? +quantity : null, unit, description };
// });
const ingredients = formatIngredientsArr(newRecipe);
const recipe = {
title: newRecipe.title,
source_url: newRecipe.sourceUrl,
image_url: newRecipe.image,
publisher: newRecipe.publisher,
cooking_time: +newRecipe.cookingTime,
servings: +newRecipe.servings,
servings: SERVINGS_TO_UPLOAD,
ingredients,
};
const data = await AJAX(`${API_URL}?key=${API_KEY}`, recipe);
const data = await AJAX(API_URLS.data, recipe, `application/json`);
state.recipe = createRecipeObject(data);
addBookmark(state.recipe);
} catch (err) {
console.log(err);
throw err;
}
};

init();
11 changes: 7 additions & 4 deletions src/sass/_bookmark.scss
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
.bookmarks {
padding: 1rem 0;
@include position(absolute, null, -2.5rem, null, null);
@include position(absolute, null, -2.9rem, null, null);
@include visibility(hidden, 0);
z-index: 10;
width: 38rem;
max-height: 370px;
background-color: #fff;
box-shadow: 0 0.8rem 5rem 2rem rgba($color-grey-dark-1, 0.1);
transition: all 0.5s 0.2s;
overflow-y: scroll;
max-height: 370px;

@media screen and (max-width: $bp-medium) {
max-height: 300px;
width: 35rem;
right: -3.9rem;
}

@media screen and (max-width: $bp-small) {
width: 31rem;
right: 0rem;
top: 7.8rem;
}

@media screen and (max-width: $bp-smallest) {
width: 35rem;
}

&__list {
list-style: none;
Expand Down
2 changes: 1 addition & 1 deletion src/sass/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
font-weight: 600;

@media only screen and (max-width: $bp-medium) {
padding: 1.5rem 2.5rem;
padding: 1.5rem 2.3rem;
}

svg {
Expand Down
Loading

0 comments on commit fd5f1f4

Please sign in to comment.