Spaces:
Sleeping
Sleeping
| const express = require("express"); | |
| const { generateIQC } = require("iqc-canvas"); | |
| const app = express(); | |
| const PORT = process.env.PORT || 7860; | |
| /* ============================= */ | |
| /* RAW ENDPOINT /api */ | |
| /* ============================= */ | |
| app.get("/api", async (req, res) => { | |
| try { | |
| const { text, time, battery } = req.query; | |
| if (!text || !time) { | |
| return res.status(400).json({ | |
| error: 'Gunakan: /api?text=Halo&time=12.30&battery=90' | |
| }); | |
| } | |
| const result = await generateIQC(text, time, { | |
| baterai: [true, battery || "100"], | |
| operator: true, | |
| timebar: true, | |
| wifi: true | |
| }); | |
| res.setHeader("Content-Type", result.mimeType); | |
| res.send(result.image); | |
| } catch (err) { | |
| res.status(500).json({ error: err.message }); | |
| } | |
| }); | |
| /* ============================= */ | |
| /* UI PREMIUM ROOT / */ | |
| /* ============================= */ | |
| app.get("/", async (req, res) => { | |
| res.send(` | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>IQC Canvas Premium</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;800&display=swap" rel="stylesheet"> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Poppins', sans-serif; | |
| } | |
| body { | |
| min-height: 100vh; | |
| background: linear-gradient(135deg, #0f0c29, #302b63, #24243e); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| color: white; | |
| padding: 20px; | |
| } | |
| /* ================= RESPONSIVE CONTAINER ================= */ | |
| .container { | |
| width: 100%; | |
| max-width: 650px; | |
| padding: clamp(20px, 5vw, 40px); | |
| border-radius: clamp(15px, 3vw, 25px); | |
| backdrop-filter: blur(25px); | |
| background: rgba(255,255,255,0.05); | |
| box-shadow: 0 0 60px rgba(0,0,0,0.6); | |
| text-align: center; | |
| transition: 0.3s ease; | |
| } | |
| /* ================= RESPONSIVE TITLE ================= */ | |
| h1 { | |
| font-size: clamp(20px, 5vw, 28px); | |
| font-weight: 800; | |
| margin-bottom: clamp(20px, 4vw, 30px); | |
| background: linear-gradient(90deg,#00f5ff,#7b2ff7); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| /* ================= INPUT ================= */ | |
| input { | |
| width: 100%; | |
| padding: clamp(10px, 3vw, 14px); | |
| margin: 10px 0; | |
| border-radius: clamp(10px, 3vw, 15px); | |
| border: none; | |
| outline: none; | |
| background: rgba(255,255,255,0.1); | |
| color: white; | |
| font-size: clamp(13px, 3.5vw, 14px); | |
| } | |
| /* ================= BUTTON ================= */ | |
| button { | |
| width: 100%; | |
| padding: clamp(10px, 3vw, 14px); | |
| margin-top: 15px; | |
| border-radius: clamp(10px, 3vw, 15px); | |
| border: none; | |
| cursor: pointer; | |
| font-weight: 600; | |
| font-size: clamp(14px, 3.5vw, 15px); | |
| background: linear-gradient(90deg,#00f5ff,#7b2ff7); | |
| color: white; | |
| transition: 0.3s; | |
| } | |
| button:hover { | |
| transform: scale(1.03); | |
| box-shadow: 0 0 25px #7b2ff7; | |
| } | |
| /* ================= PREVIEW ================= */ | |
| .preview { | |
| margin-top: clamp(20px, 4vw, 30px); | |
| display: none; | |
| } | |
| .preview img { | |
| width: 100%; | |
| max-width: 350px; | |
| height: auto; | |
| border-radius: clamp(15px, 3vw, 20px); | |
| box-shadow: 0 0 40px rgba(0,0,0,0.6); | |
| transition: 0.3s; | |
| } | |
| /* ================= FOOTER ================= */ | |
| .footer { | |
| margin-top: clamp(15px, 4vw, 25px); | |
| font-size: clamp(11px, 3vw, 12px); | |
| opacity: 0.6; | |
| } | |
| /* ================= EXTRA BREAKPOINTS ================= */ | |
| /* Tablet */ | |
| @media (min-width: 768px) { | |
| .container { | |
| max-width: 550px; | |
| } | |
| } | |
| /* Desktop */ | |
| @media (min-width: 1200px) { | |
| .container { | |
| max-width: 650px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>IQC Canvas Generator</h1> | |
| <input type="text" id="text" placeholder="Masukkan text chat..." /> | |
| <input type="text" id="time" placeholder="Waktu (contoh 12.30)" /> | |
| <input type="number" id="battery" placeholder="Battery %" value="100" /> | |
| <button onclick="generateImage()">Generate Image</button> | |
| <div class="preview" id="preview"> | |
| <img id="resultImage"/> | |
| </div> | |
| <div class="footer"> | |
| Premium UI • Auto Preview • Endpoint /api | |
| </div> | |
| </div> | |
| <script> | |
| async function generateImage() { | |
| const text = document.getElementById("text").value; | |
| const time = document.getElementById("time").value; | |
| const battery = document.getElementById("battery").value; | |
| if (!text || !time) { | |
| alert("Text dan Time wajib diisi!"); | |
| return; | |
| } | |
| const url = "/api?text=" + encodeURIComponent(text) | |
| + "&time=" + encodeURIComponent(time) | |
| + "&battery=" + encodeURIComponent(battery); | |
| const response = await fetch(url); | |
| const blob = await response.blob(); | |
| const imageUrl = URL.createObjectURL(blob); | |
| document.getElementById("resultImage").src = imageUrl; | |
| document.getElementById("preview").style.display = "block"; | |
| } | |
| </script> | |
| </body> | |
| </html> | |
| `); | |
| }); | |
| app.listen(PORT, () => { | |
| console.log("Server running on port " + PORT); | |
| }); |