Compare commits
10 الالتزامات
e696f2f4cd
...
main
المؤلف | SHA1 | التاريخ | |
---|---|---|---|
ac1b26a5c4 | |||
576a11bcda | |||
6073856421 | |||
174399a81e | |||
d9741b878a | |||
7e7a593bf6 | |||
227a985c2f | |||
dbf92521ff | |||
f234eb7344 | |||
43831eb01a |
29
README.md
29
README.md
@@ -0,0 +1,29 @@
|
||||
# Prayer Times App
|
||||
|
||||
A simple app to get prayer times by city and country using the [Aladhan API](https://aladhan.com/prayer-times-api).
|
||||
|
||||
## Tech
|
||||
- **HTML**: `index.pug` → `index.html`
|
||||
- **CSS**: `style.sass` → `style.css`
|
||||
- **JS**: Vanilla JS with `async/await`
|
||||
- **Tools**: Pug, Sass, npm scripts
|
||||
|
||||
___
|
||||
|
||||
## Features
|
||||
- Search prayer times by **city** and **country**
|
||||
- Toggle to show **5 main prayers** or **all prayer times**
|
||||
- Clean, modern UI with mobile-friendly design
|
||||
- Auto-focus and instant feedback
|
||||
- Built with **Pug**, **Sass**, and vanilla **JavaScript**
|
||||
|
||||
___
|
||||
|
||||
## How to Run
|
||||
Just Click [**On This Link**](https://muhammadfarouk12.github.io/prayingApi/)
|
||||
___
|
||||
|
||||
## Notes
|
||||
- `app.commented.js` is a fully documented version of the logic — great for learning or future reference.
|
||||
- The app uses async/await with try/catch for safe API error handling.
|
||||
- Focus management improves user experience on mobile.
|
||||
|
77
app.commented.js
Normal file
77
app.commented.js
Normal file
@@ -0,0 +1,77 @@
|
||||
// Focus on the city input field when the page loads (UX improvement)
|
||||
city.focus();
|
||||
|
||||
/**
|
||||
* Fetches and displays prayer times for a given city and country.
|
||||
*
|
||||
* @param {string} city - The name of the city (e.g., "London")
|
||||
* @param {string} countryCode - The country code (e.g., "UK")
|
||||
* @param {boolean} wantsAll - If true, show all prayer times; if false, show only 5 main ones
|
||||
*
|
||||
* Uses the Aladhan API to get Islamic prayer times.
|
||||
*/
|
||||
async function getTimes(city, countryCode, wantsAll) {
|
||||
// Refocus on the city input (keeps UX consistent, especially on mobile)
|
||||
document.getElementById("city").focus();
|
||||
|
||||
// Update the UI to show which city and country are being used
|
||||
document.getElementById("show_city").innerText = city.toUpperCase() + " City ";
|
||||
document.getElementById("show_country").innerText = countryCode.toUpperCase() + " Country";
|
||||
|
||||
try {
|
||||
// Construct the API URL with city and country, then fetch data
|
||||
const response = await fetch(`https://api.aladhan.com/v1/timingsByCity?city=${city}&country=${countryCode}`);
|
||||
|
||||
// Parse the JSON response from the API
|
||||
const parsedResponse = await response.json();
|
||||
|
||||
// Extract the prayer times from the response
|
||||
const times = parsedResponse.data.timings;
|
||||
|
||||
// This will hold the HTML for the list of prayer times
|
||||
let container = "";
|
||||
|
||||
// Counter to track position in the times object (used when filtering to 5 prayers)
|
||||
let current = 0;
|
||||
|
||||
// Loop through each prayer time (e.g., Fajr, Dhuhr, etc.)
|
||||
for (const time in times) {
|
||||
if (wantsAll) {
|
||||
// If user wants all times, display every prayer
|
||||
container += `<li><span class="cell">${time}</span><span class="cell">${times[time]}</span></li>`;
|
||||
} else {
|
||||
// Otherwise, show only the 5 main prayers: Fajr, Dhuhr, Asr, Maghrib, Isha
|
||||
// These correspond to indices: 0=Fajr, 2=Dhuhr, 3=Asr, 5=Maghrib, 6=Isha
|
||||
const fiveTimes = [0, 2, 3, 5, 6];
|
||||
if (fiveTimes.includes(current)) {
|
||||
container += `<li><span class="cell">${time}</span><span class="cell">${times[time]}</span></li>`;
|
||||
}
|
||||
current++; // Increment counter for each prayer
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the generated HTML into the page
|
||||
document.getElementById("times_container").innerHTML = container;
|
||||
|
||||
} catch (err) {
|
||||
// If the fetch fails (network error, invalid city, etc.), log the error
|
||||
console.log("Failed: " + err.message);
|
||||
// Optional: show user-friendly message in UI
|
||||
document.getElementById("times_container").innerHTML =
|
||||
`<li class="error">Failed to load prayer times. Check city/country and try again.</li>`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach click event to the "Get Times" button.
|
||||
* When clicked, calls getTimes() with:
|
||||
* - city input value
|
||||
* - country code input value
|
||||
* - whether the "Show All" checkbox is checked
|
||||
*/
|
||||
document.getElementById("getTimes").onclick = () =>
|
||||
getTimes(
|
||||
city.value,
|
||||
code.value,
|
||||
document.getElementById("wantsAll").checked
|
||||
);
|
29
app.js
29
app.js
@@ -0,0 +1,29 @@
|
||||
city.focus();
|
||||
async function getTimes(city, countryCode, wantsAll){
|
||||
document.getElementById("city").focus()
|
||||
document.getElementById("show_city").innerText = city.toUpperCase() + " City "
|
||||
document.getElementById("show_country").innerText = countryCode.toUpperCase() + " Country"
|
||||
try {
|
||||
const response = await fetch(`https://api.aladhan.com/v1/timingsByCity?city=${city}&country=${countryCode}`)
|
||||
const parsedResponse = await response.json();
|
||||
const times = parsedResponse.data.timings
|
||||
let container = ""
|
||||
let current = 0
|
||||
for (const time in times) {
|
||||
if (wantsAll) {
|
||||
container += `<li><span class="cell">${time}</span><span class="cell">${times[time]}</span></li>`
|
||||
} else {
|
||||
const fiveTimes = [0, 2, 3, 5, 6]
|
||||
if(fiveTimes.includes(current)){
|
||||
container += `<li><span class="cell">${time}</span><span class="cell">${times[time]}</span></li>`
|
||||
}
|
||||
current++
|
||||
}
|
||||
}
|
||||
document.getElementById("times_container").innerHTML = container
|
||||
} catch(err){
|
||||
console.log("Faild: " + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("getTimes").onclick = ()=> getTimes(city.value, code.value, document.getElementById("wantsAll").checked)
|
||||
|
27
index.html
27
index.html
@@ -1 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Praying Times </title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Get Praying Times Anywhere </h1>
|
||||
<div class="block">
|
||||
<label id="city_label">Enter Your City Name</label>
|
||||
<input id="city">
|
||||
</div>
|
||||
<div class="block">
|
||||
<label id="code_label">Enter The Country Code</label>
|
||||
<input id="code">
|
||||
</div>
|
||||
<div class="show_all">
|
||||
<label for="wantsAll">Do you want to show all times ? uncheck the box to get only the 5 prayings</label>
|
||||
<input id="wantsAll" type="checkbox" name="wantsAll">
|
||||
</div>
|
||||
<div class="show">
|
||||
<button id="getTimes">Get Times</button>
|
||||
<h3>Here is the praying times of <span id="show_city"> ____________ </span>City, and <span id="show_country">______ </span>country</h3>
|
||||
<ul id="times_container"></ul>
|
||||
</div>
|
||||
</body>
|
||||
<script src="app.js"></script>
|
||||
</html>
|
25
index.pug
25
index.pug
@@ -1 +1,26 @@
|
||||
doctype
|
||||
html
|
||||
head
|
||||
title Praying Times
|
||||
link(rel="stylesheet", href="style.css")
|
||||
body
|
||||
h1 Get Praying Times Anywhere
|
||||
|
||||
.block
|
||||
label#city_label Enter Your City Name
|
||||
input#city
|
||||
.block
|
||||
label#code_label Enter The Country Code
|
||||
input#code
|
||||
.show_all
|
||||
label(for="wantsAll") Do you want to show all times ? uncheck the box to get only the 5 prayings
|
||||
input#wantsAll(type="checkbox", name="wantsAll")
|
||||
.show
|
||||
button#getTimes Get Times
|
||||
h3 Here is the praying times of
|
||||
span#show_city ____________
|
||||
| City, and
|
||||
span#show_country ______
|
||||
| country
|
||||
ul#times_container
|
||||
script(src="app.js")
|
||||
|
74
style.css
74
style.css
@@ -1,3 +1,77 @@
|
||||
* {
|
||||
font-family: sans-serif;
|
||||
color: #1E1C06;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #E1DC9F;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 20px auto;
|
||||
width: min(800px, 90%);
|
||||
}
|
||||
|
||||
input:not([type=checkbox]) {
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
input:not([type=checkbox]):focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin: 0px 0 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
background-color: #998768;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
width: max(220px, 100%);
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #991111;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cell {
|
||||
border: 3px solid #991111;
|
||||
padding: 10px 20px;
|
||||
display: inline-block;
|
||||
margin: 10px -1px;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.show_all {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
.show_all input {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=style.css.map */
|
||||
|
@@ -1 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"","file":"style.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["style.sass"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;;;AAEF;EACE;;;AACF;EACE;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AACF;EACE;EACA;EACA;EACA;;AACA;EACE;;;AAEJ;EACE;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AACF;EACE;;;AACF;EACE;EACA;;;AACF;EACE;EACA;EACA;EACA;EACA;EACA;;;AACF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA","file":"style.css"}
|
79
style.sass
79
style.sass
@@ -0,0 +1,79 @@
|
||||
*
|
||||
font-family: sans-serif
|
||||
color: #1E1C06
|
||||
box-sizing: border-box
|
||||
|
||||
h1
|
||||
text-align: center
|
||||
h3
|
||||
text-align: center
|
||||
|
||||
body
|
||||
background-color: #E1DC9F
|
||||
|
||||
div
|
||||
margin: 20px auto
|
||||
width: min(800px, 90%)
|
||||
input:not([type=checkbox])
|
||||
padding: 10px 20px
|
||||
border-radius: 5px
|
||||
border: none
|
||||
width: 100%
|
||||
&:focus
|
||||
outline: none
|
||||
input[type=checkbox]
|
||||
label
|
||||
display: block
|
||||
margin: 0px 0 10px
|
||||
|
||||
button
|
||||
padding: 10px 20px
|
||||
background-color: #998768;
|
||||
border: none
|
||||
border-radius: 5px
|
||||
width: max(220px, 100%)
|
||||
margin: 20px auto
|
||||
li
|
||||
list-style: none
|
||||
span
|
||||
color: #991111
|
||||
font-weight: bold
|
||||
.cell
|
||||
border: 3px solid #991111
|
||||
padding: 10px 20px
|
||||
display: inline-block
|
||||
margin: 10px -1px
|
||||
width: 50%
|
||||
text-align: center
|
||||
.show_all
|
||||
text-align: center
|
||||
display: flex
|
||||
justify-content: center
|
||||
gap: 20px
|
||||
label
|
||||
input
|
||||
width: 20px
|
||||
height: 20px
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
المرجع في مشكلة جديدة
حظر مستخدم