Upload files to "/"
This commit is contained in:
commit
f5af2b4da8
83
README.md
Normal file
83
README.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<h1 align="left">Payme.sol: Seamless POS for Solana Payments</h1>
|
||||||
|
|
||||||
|
Payme.sol is a mobile decentralized application (dApp) designed to simplify the process of accepting payments on the Solana blockchain. Built as a Point-of-Sale (POS) system, Payme.sol enables small business owners and individuals to receive payments securely and efficiently through a streamlined, user-friendly experience.
|
||||||
|
|
||||||
|
<h1 align="left">How It Works</h1>
|
||||||
|
|
||||||
|
With Payme.sol, accepting payments is effortless:
|
||||||
|
|
||||||
|
-Generate QR Codes: Create QR codes that embed all necessary payment details, including the amount and your wallet address.
|
||||||
|
|
||||||
|
-Scan and Pay: Customers scan the QR code using their smartphone camera, which automatically opens their Phantom wallet with pre-filled transaction details.
|
||||||
|
|
||||||
|
-Confirm with Ease: Customers review and confirm the payment with a single tap, eliminating manual input and reducing the risk of errors.
|
||||||
|
|
||||||
|
This seamless process ensures a fast and accurate payment experience, making Payme.sol an ideal solution for businesses and individuals alike.
|
||||||
|
|
||||||
|
<h1 align="left">Open-Source and Secure</h1>
|
||||||
|
|
||||||
|
Payme.sol is an open-source project, fostering transparency and collaboration within the global developer community. This approach allows for continuous improvements and rigorous code review, enhancing security by enabling vulnerabilities to be identified and resolved promptly. By leveraging the Solana blockchain, Payme.sol ensures transactions are fast, cost-effective, and secure.
|
||||||
|
|
||||||
|
<h3 align="left">Current Features and Future Vision</h3>
|
||||||
|
|
||||||
|
-Euro-to-Crypto Conversions: Payme.sol currently supports conversions from Euro to cryptocurrency, facilitating easy transactions for users.
|
||||||
|
|
||||||
|
-Expanding Currency Support: We are actively working to include additional currencies, aiming to make Payme.sol a versatile and accessible payment solution for users worldwide, regardless of their preferred currency
|
||||||
|
|
||||||
|
<h1 align="left">Getting Started</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 align="left">1. Install Phantom Wallet</h3>
|
||||||
|
|
||||||
|
|
||||||
|
Phantom Wallet is available as a mobile app (iOS, Android) or a browser extension (Chrome, Firefox). Download it from the official website https://phantom.com and follow the on-screen instructions to create a new wallet or import an existing one.
|
||||||
|
|
||||||
|
<h3 align="left">2. Generate Your Payment QR Code</h3>
|
||||||
|
|
||||||
|
-Open the https://paymesol.app on your mobile device or browser.
|
||||||
|
|
||||||
|
-Choose your preferred version of the Payme.sol application: Basic (available now) or Pro (coming soon with enhanced features).
|
||||||
|
|
||||||
|
-Click the "Connect Wallet" button and follow the on-screen instructions to securely connect your Phantom wallet to Payme.sol. Connecting your wallet to Payme.sol is only to securely retrieve your wallet address, which is used to generate the QR code. We do not have access to your wallet or your funds.
|
||||||
|
|
||||||
|
-Choose the Cryptocurrency you want to receive the payment in (e.g., EURC, SOL, USDC).
|
||||||
|
|
||||||
|
-Enter the amount you want to receive in Euros. (Other currencies will be supported in the future).
|
||||||
|
|
||||||
|
-Click "Generate QR Code" button to create a unique QR code containing all the payment information.
|
||||||
|
|
||||||
|
<h3 align="left">3. Receive the Payment</h3>
|
||||||
|
|
||||||
|
-The payer must have the cryptocurrency you choose available in their wallet.
|
||||||
|
|
||||||
|
-The payer scans the QR code with their smartphone camera.
|
||||||
|
|
||||||
|
-The QR code will automatically open their Phantom wallet.
|
||||||
|
|
||||||
|
-The payer reviews the payment details and confirms the transaction.
|
||||||
|
|
||||||
|
-You will receive the payment in your Phantom wallet.
|
||||||
|
|
||||||
|
<h3 align="left">That's it! You've successfully received a payment using Payme.sol.</h3>
|
||||||
|
|
||||||
|
<h4 align="left">Always verify the payment information before proceeding.Remember, blockchain transactions are irreversible.</h4>
|
||||||
|
|
||||||
|
<h2 align="left">Documentation: https://docs.paymesol.app</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://linktr.ee/debrosofficial" target="_blank">
|
||||||
|
<img src="https://img.shields.io/static/v1?message=Linktree&logo=linktree&label=&color=1de9b6&logoColor=white&labelColor=&style=for-the-badge" height="35" alt="linktree logo" />
|
||||||
|
</a>
|
||||||
|
<a href="https://x.com/debrosofficial" target="_blank">
|
||||||
|
<img src="https://img.shields.io/static/v1?message=Twitter&logo=twitter&label=&color=1DA1F2&logoColor=white&labelColor=&style=for-the-badge" height="35" alt="twitter logo" />
|
||||||
|
</a>
|
||||||
|
<a href="https://t.me/debrosportal" target="_blank">
|
||||||
|
<img src="https://img.shields.io/static/v1?message=Telegram&logo=telegram&label=&color=2CA5E0&logoColor=white&labelColor=&style=for-the-badge" height="35" alt="telegram logo" />
|
||||||
|
</a>
|
||||||
|
<a href="https://www.youtube.com/@DeBrosOfficial" target="_blank">
|
||||||
|
<img src="https://img.shields.io/static/v1?message=Youtube&logo=youtube&label=&color=FF0000&logoColor=white&labelColor=&style=for-the-badge" height="35" alt="youtube logo" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
###
|
18922
package-lock.json
generated
Normal file
18922
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
102
service-worker.js
Normal file
102
service-worker.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
const CACHE_NAME = 'paymesol-cache-v1';
|
||||||
|
const ASSETS_TO_CACHE = [
|
||||||
|
'/',
|
||||||
|
'/index.html',
|
||||||
|
'/styles.css',
|
||||||
|
'/index.js',
|
||||||
|
'/manifest.json',
|
||||||
|
'/icons/paymesol-500x500.png',
|
||||||
|
'/images/eurc-icon.png',
|
||||||
|
'/images/solana2-logo.png',
|
||||||
|
'/images/usdc-icon.png',
|
||||||
|
'/images/paymesol.png',
|
||||||
|
'/images/phantom.png',
|
||||||
|
'/images/help.png',
|
||||||
|
'/images/debros.png',
|
||||||
|
'/images/history.png'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Install Event: Cache static assets
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
console.log('Service Worker: Cache opened');
|
||||||
|
return cache.addAll(ASSETS_TO_CACHE).catch(err => {
|
||||||
|
console.error('Service Worker: Cache addAll failed', err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch Event: Handle API calls and static assets
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
|
||||||
|
// API Endpoints
|
||||||
|
const apiEndpoints = [
|
||||||
|
'https://api.mainnet-beta.solana.com',
|
||||||
|
'https://api.coingecko.com/api/v3/simple/price'
|
||||||
|
];
|
||||||
|
|
||||||
|
if (apiEndpoints.some(endpoint => url.origin === endpoint || url.href.includes(endpoint))) {
|
||||||
|
// Network-first for API calls
|
||||||
|
event.respondWith(
|
||||||
|
fetch(event.request)
|
||||||
|
.then((networkResponse) => {
|
||||||
|
return caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
cache.put(event.request, networkResponse.clone());
|
||||||
|
return networkResponse;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.warn('Service Worker: Network fetch failed, falling back to cache', url.href);
|
||||||
|
return caches.match(event.request).then((cachedResponse) => {
|
||||||
|
if (cachedResponse) return cachedResponse;
|
||||||
|
return new Response(JSON.stringify({ error: 'Offline and no cached data available' }), {
|
||||||
|
status: 503,
|
||||||
|
statusText: 'Service Unavailable'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Cache-first for static assets
|
||||||
|
event.respondWith(
|
||||||
|
caches.match(event.request).then((response) => {
|
||||||
|
if (response) {
|
||||||
|
console.log('Service Worker: Serving from cache', url.href);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return fetch(event.request).then((networkResponse) => {
|
||||||
|
return caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
cache.put(event.request, networkResponse.clone());
|
||||||
|
return networkResponse;
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
console.error('Service Worker: Fetch failed for', url.href);
|
||||||
|
return new Response('Offline and resource not cached', {
|
||||||
|
status: 503,
|
||||||
|
statusText: 'Service Unavailable'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Activate Event: Clean up old caches
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
const cacheWhitelist = [CACHE_NAME];
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then((cacheNames) => {
|
||||||
|
return Promise.all(
|
||||||
|
cacheNames.map((cacheName) => {
|
||||||
|
if (!cacheWhitelist.includes(cacheName)) {
|
||||||
|
console.log('Service Worker: Deleting old cache', cacheName);
|
||||||
|
return caches.delete(cacheName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
474
styles.css
Normal file
474
styles.css
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
/* ========================================================================== */
|
||||||
|
/* General Reset and Base Styles */
|
||||||
|
/* ========================================================================== */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 95vh;
|
||||||
|
background: #ab9ff2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Main Container */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.app-container {
|
||||||
|
background: #222222;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||||
|
width: 325px;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
height: 610px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Logo and Title */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.logo-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Header (Wallet Connect and Menu Button) */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.header-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1001;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-wallet {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #3c315b;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-wallet:hover {
|
||||||
|
background-color: #50597b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #3a3a4a;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s;
|
||||||
|
height: 35px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button span {
|
||||||
|
display: block;
|
||||||
|
width: 25px;
|
||||||
|
height: 3px;
|
||||||
|
background: #ffffff;
|
||||||
|
position: absolute;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button span:nth-child(1) {
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button span:nth-child(2) {
|
||||||
|
top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button span:nth-child(3) {
|
||||||
|
top: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button.active span:nth-child(1) {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button.active span:nth-child(2) {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button.active span:nth-child(3) {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-button:hover {
|
||||||
|
background-color: #444d50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Menu Dropdown */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.menu-dropdown {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 105px;
|
||||||
|
right: 15px;
|
||||||
|
width: 160px;
|
||||||
|
background: #3a3a4a;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 1000;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-dropdown.active {
|
||||||
|
display: block;
|
||||||
|
animation: slideIn 0.3s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-dropdown.closing {
|
||||||
|
animation: slideOut 0.3s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-dropdown button, .menu-dropdown a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid #4a436b;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-dropdown button:hover, .menu-dropdown a:hover {
|
||||||
|
background: #ab9ff2;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-dropdown button:last-child, .menu-dropdown a:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-dropdown img {
|
||||||
|
width: 25px;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 6px;
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
|
@keyframes slideIn {
|
||||||
|
from {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideOut {
|
||||||
|
from {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Cryptocurrency Selection */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.radio-dropdown {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-dropdown input[type="radio"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-dropdown label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #3a3a4a;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s, color 0.2s;
|
||||||
|
border: 1px solid #3a3a4a;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-dropdown label:hover {
|
||||||
|
background-color: #444d50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-dropdown input[type="radio"]:checked + label {
|
||||||
|
background-color: #2ec08b;
|
||||||
|
border-color: #2ec08b;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 25px;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Input Fields Container */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.amount-container {
|
||||||
|
width: 100%;
|
||||||
|
background: #1a1a2e;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 320px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currency-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currency-label {
|
||||||
|
width: 60px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.euro-display {
|
||||||
|
width: 180px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
text-align: right;
|
||||||
|
padding: 5px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #ffffff;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crypto-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crypto-display {
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
text-align: right;
|
||||||
|
padding: 5px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #2ec08b;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crypto-display.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crypto-label {
|
||||||
|
color: #2ec08b;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Keypad */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.keypad {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 15px;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keypad button {
|
||||||
|
padding: 13px 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
background: #2a2a2a;
|
||||||
|
color: #ffffff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: 0 0 5px rgba(171, 159, 242, 0.5),
|
||||||
|
0 0 10px rgba(171, 159, 242, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.keypad button:hover {
|
||||||
|
background: #3a3a4a;
|
||||||
|
box-shadow: 0 0 8px rgba(171, 159, 242, 0.8),
|
||||||
|
0 0 15px rgba(171, 159, 242, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Generate QR Button Container */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.payment-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#generate-qr {
|
||||||
|
flex: 1;
|
||||||
|
width: 135px;
|
||||||
|
height: 50px;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: linear-gradient(145deg, #2ec08b, #25a671);
|
||||||
|
color: white;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#generate-qr:hover {
|
||||||
|
background: linear-gradient(145deg, #34d698, #2ec08b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Modals (QR, History) */
|
||||||
|
/* ========================================================================== */
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 2000;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: #fefefe;
|
||||||
|
margin: 15% auto;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #888;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 320px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
color: #aaa;
|
||||||
|
float: right;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close:hover,
|
||||||
|
.close:focus {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qr-modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 999;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qr-modal .modal-content {
|
||||||
|
background-color: #2ec08b;
|
||||||
|
text-align: center;
|
||||||
|
display: grid;
|
||||||
|
justify-content: center;
|
||||||
|
position: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qr-modal .modal-content h3 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button {
|
||||||
|
background-color: #ff7243;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 15px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qr-canvas {
|
||||||
|
margin-top: 10px;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user