Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 7 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Currency and Weight Converter
# Currency Converter

1. **Currency Conversion**:
- Convert prices from one currency to another.
Expand All @@ -19,15 +19,9 @@
- Uses real API endpoint (`https://api.frankfurter.dev/v2/rates`) to get the latest exchange rates.
- Displays the last updated time for the exchange rate.

1. **Weight-Based Price Calculations**:
- Calculate price per kilogram for a given weight.
- Calculate price for a specific unit weight (e.g., 250g).
- For example: compare prices in supermarket:
* enter price in PLN
* add weight for 200g in PLN
* converts to kilogram price in EUR
* add weight for 250g in EUR
* converts to 250g price in EUR
1. **Optional Price per Weight Calculations**:
- Calculate price per kilogram when weight is provided
- Compare products by weight (e.g., 200g vs 250g packages)

1. **Localization**:
- Automatically detects browser language and switches between English and German.
Expand All @@ -47,16 +41,13 @@
1. Select the **current currency** and the **target currency**.
1. (Optional) Add a **bank markup percentage** to adjust the exchange rate (positive values reduce the rate, negative values increase it).
1. Enter the **price** in the current currency.
1. (Optional) Add the product's **weight** and a **custom unit weight** (e.g., 250g).
1. The app will calculate:
- Price in the target currency.
- Price per kilogram (if weight is provided).
- Price for the specified unit in **target currency** (if unit weight is provided).
1. (Optional) Enter **weight** to calculate price per kilogram
1. The app shows the price in the target currency
1. Click the 🔄 button to fetch the latest exchange rates.
1. Use the 🧹 button to reset all input fields while preserving your currency preferences.

Access the app directly from GitHub Pages:
👉 [Currency and Weight Converter](https://leneffets.github.io/currency/)
👉 [Currency Converter](https://leneffets.github.io/currency/)

## Screenshot
![image](https://github.com/user-attachments/assets/a1d71a72-45cc-4436-a050-f4c4cbb8373b)
Expand Down
Binary file added currency_192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added currency_512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Currency and Weight Converter</title>
<meta name="theme-color" content="#2d2d2d">
<meta name="description" content="Currency Converter - Convert currencies and calculate prices per weight">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="Currency Converter">
<title>Currency Converter</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<link rel="icon" type="image/png" href="favicon.png"/>
<link rel="apple-touch-icon" href="favicon.png">
<link rel="manifest" href="manifest.json">
<script src="script.js"></script>

</head>
<body>
<div class="container">
Expand Down Expand Up @@ -76,6 +82,7 @@
<div class="exchange-info" id="exchangeInfo"></div>

<div class="output" id="output"></div>
<button id="installButton" class="install-badge" style="display:none;" title="Install app">📱 Install the app</button>
</div>
</body>
</html>
23 changes: 23 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "Currency Converter",
"short_name": "Currency Converter",
"description": "Convert currencies and calculate prices per weight",
"start_url": "/",
"display": "standalone",
"background_color": "#f4f4f9",
"theme_color": "#2d2d2d",
"orientation": "portrait-primary",
"icons": [
{
"src": "currency_192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "currency_512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"categories": ["finance", "utilities"]
}
36 changes: 36 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,29 @@ function resetInputs() {
if (priceEl) priceEl.focus();
}

// Capture install prompt
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
const installBtn = document.getElementById('installButton');
if (installBtn) {
installBtn.style.display = 'block';
}
});



window.addEventListener('appinstalled', () => {
deferredPrompt = null;
});

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').catch((err) => console.error('SW registration failed:', err));
}



// Initialize the app (wait for DOM ready before touching DOM)
(async function initializeApp() {
if (document.readyState === 'loading') {
Expand All @@ -232,6 +255,19 @@ function resetInputs() {
await loadLocale(userLanguage);
loadCurrencySettings();

// Setup install button
const installBtn = document.getElementById('installButton');
if (installBtn) {
installBtn.addEventListener('click', async () => {
if (deferredPrompt) {
deferredPrompt.prompt();
await deferredPrompt.userChoice;
deferredPrompt = null;
installBtn.style.display = 'none';
}
});
}

// initial exchange rate fetch (debounced wrapper)
updateExchangeRate();
})();
25 changes: 25 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,35 @@ body {
border-radius: 8px;
box-shadow: 0 2px 10px var(--shadow-color);
transition: background-color 0.3s ease, box-shadow 0.3s ease;
overflow: auto;
}

h1 {
text-align: center;
margin: 0 0 20px 0;
}

.install-badge {
background: none;
border: 1px solid #2d7ef2;
color: #2d7ef2;
border-radius: 4px;
padding: 6px 10px;
font-size: 0.85em;
cursor: pointer;
display: inline-block;
transition: all 0.3s ease;
margin-top: 15px;
float: right;
}

.install-badge:hover {
background: #2d7ef2;
color: #ffffff;
}

.install-badge:active {
transform: scale(0.95);
}

label {
Expand Down
41 changes: 41 additions & 0 deletions sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const CACHE_NAME = 'currency-converter-v1';
const ASSETS = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'/favicon.png',
'/manifest.json',
'/currency_192.png',
'/currency_512.png',
'/locales/en.json',
'/locales/de.json'
];

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
);
self.skipWaiting();
});

self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))
)
);
self.clients.claim();
});

self.addEventListener('fetch', (event) => {
if (event.request.url.includes('api.frankfurter')) {
event.respondWith(
fetch(event.request).catch(() => caches.match(event.request))
);
return;
}
event.respondWith(
caches.match(event.request).then((response) => response || fetch(event.request))
);
});
Loading