From 20cfa7979382125af3d6823da883ffe1710b330a Mon Sep 17 00:00:00 2001
From: Ravindrayadav04
Date: Tue, 24 Feb 2026 21:26:15 +0530
Subject: [PATCH 1/6] fix the bug related to visit count and change the ui also
---
.env.sample | 4 +-
app/main.py | 32 +
app/static/style.css | 1715 +++++++++++++++++++------------------
app/templates/recent.html | 17 +-
app/utils/cache.py | 21 +-
app/utils/config.py | 5 +-
app/utils/db.py | 40 +-
7 files changed, 987 insertions(+), 847 deletions(-)
diff --git a/.env.sample b/.env.sample
index bc9711c..24e1e91 100644
--- a/.env.sample
+++ b/.env.sample
@@ -2,5 +2,5 @@ MODE=local
MONGO_URI=mongodb://:@127.0.0.1:27017/?authSource=admin&retryWrites=true&w=majority
DOMAIN=https://localhost:8001
PORT=8001
-API_VERSION=""
-APP_NAMe="LOCAL"
\ No newline at end of file
+API_VERSION="/api/v1"
+APP_NAME="LOCAL"
\ No newline at end of file
diff --git a/app/main.py b/app/main.py
index 8f393ba..0779b02 100644
--- a/app/main.py
+++ b/app/main.py
@@ -216,12 +216,44 @@ async def delete_url(request: Request, short_code: str):
return PlainTextResponse("", status_code=204)
+#@app.get("/{short_code}")
+#async def redirect_short(request: Request, short_code: str):
+# logger = logging.getLogger(__name__)
+# # Try cache first
+# cached_url = get_from_cache(short_code)
+# if cached_url:
+# return RedirectResponse(cached_url)
+
+# # Check if database is connected
+# if not db.is_connected():
+# logger.warning(f"Database not connected, cannot redirect {short_code}")
+# return PlainTextResponse(
+# "Service temporarily unavailable. Please try again later.",
+# status_code=503,
+# headers={"Retry-After": "30"},
+# )
+
+# # Try database
+# doc = db.increment_visit(short_code)
+# if doc:
+# set_cache_pair(short_code, doc["original_url"])
+# return RedirectResponse(doc["original_url"])
+
+# return PlainTextResponse("Invalid or expired short URL", status_code=404)
+
@app.get("/{short_code}")
async def redirect_short(request: Request, short_code: str):
logger = logging.getLogger(__name__)
# Try cache first
cached_url = get_from_cache(short_code)
if cached_url:
+
+ if db.is_connected():
+ db.increment_visit(short_code)
+ else:
+ from app.utils.cache import increment_cache_visit
+ increment_cache_visit(short_code)
+
return RedirectResponse(cached_url)
# Check if database is connected
diff --git a/app/static/style.css b/app/static/style.css
index b754687..d32e8d9 100644
--- a/app/static/style.css
+++ b/app/static/style.css
@@ -1,815 +1,900 @@
-html,
-body {
- height: 100%;
- margin: 0;
- font-family: Arial;
- padding: 0;
- font-family: "Poppins", system-ui, Arial, sans-serif;
- background: var(--bg);
- background-size: cover;
- background-position: center;
- background-size: cover;
- background-position: center;
-}
-input {
- width: 70%;
- margin-top: 2px;
- margin-bottom: 2px;
- font-size: 16px;
-}
-.admin-box {
- margin: 120px auto 60px;
- /* space from header + footer */
-}
-.app-layout {
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- margin-top: var(--header-height);
-}
-button {
- padding: 8px;
- margin: 5px;
-}
-.error-box {
- margin-bottom: 15px;
- padding: 10px;
- color: #ff4d4d;
- border-radius: 8px;
- font-weight: 600;
-}
-
-.dark-theme h1 {
- background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
- text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
-}
-
-.dark-theme p {
- background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
- text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
-}
-.dark-theme {
- --bg-overlay: rgba(0, 0, 0, 0.75);
- --glass-bg: rgba(0, 0, 0, 0.4);
- --text-color: #fff;
- --input-bg: rgba(50, 50, 50, 0.8);
- --input-text-color: #fff;
-}
-
-@keyframes pop {
- 0% {
- transform: scale(0.7);
- opacity: 0;
- }
- 100% {
- transform: scale(1);
- opacity: 1;
- }
-}
-/* INPUT CONTAINER */
-.input-field {
- flex: 1 1 700px;
- display: flex;
- align-items: center;
- gap: 12px;
- border-radius: 12px;
- border: 2px solid rgb(6, 0, 0);
- background: transparent; /* IMPORTANT */
- padding: 12px 12px;
-}
-.dark-theme .input-field {
- border-color: #ffffff;
-}
-/* INPUT ITSELF */
-.input-field input[type="text"] {
- width: 100%;
- border: none;
- outline: none;
- background-color: transparent !important;
- background-image: none !important;
- box-shadow: none !important;
- font-size: 23px;
-}
-
-.input-field input {
- color: #000 !important;
-}
-
-.dark-theme .input-field input {
- color: #fff !important;
-}
-
-.input-field input:-webkit-autofill,
-.input-field input:-webkit-autofill:hover,
-.input-field input:-webkit-autofill:focus,
-.input-field input:-webkit-autofill:active {
- -webkit-box-shadow: 0 0 0 1000px transparent inset !important;
- box-shadow: 0 0 0 1000px transparent inset !important;
- background-color: transparent !important;
- background-image: none !important;
- transition: background-color 9999s ease-in-out 0s;
-}
-
-.input-field input:-webkit-autofill {
- -webkit-text-fill-color: #000 !important;
-}
-
-.dark-theme .input-field input:-webkit-autofill {
- -webkit-text-fill-color: #fff !important;
-}
-.input-field input::selection,
-.input-field input::-moz-selection {
- background: transparent;
- color: inherit;
-}
-.short-code {
- color: #0a0000; /* blue like links */
- font-weight: 700;
-}
-
-.app-header {
- position: fixed;
- top: 0;
- left: 0;
- width: 97%;
- height: 55px;
- background: white;
- display: flex;
- align-items: center;
- padding: 0 28px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
- z-index: 1000;
-}
-
-/* Dark mode */
-.dark-theme .app-header {
- background: linear-gradient(180deg, #0b1220, #050b14);
-}
-
-footer {
- margin-top: 0;
-}
-
-body.dark-theme,
-body.dark-theme .page,
-body.dark-theme main,
-body.dark-theme section {
- background: #0f1720 !important;
-}
-
-.header-left {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.app-logo {
- width: 36px;
- height: 36px;
- background: linear-gradient(135deg, #2563eb, #5ab9ff);
- color: white;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 18px;
-}
-
-.app-name {
- font-size: 20px;
- font-weight: 700;
- color: #111827;
-}
-
-.dark-theme .app-name {
- color: #f8fafc;
-}
-
-.header-nav {
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- gap: 26px;
-}
-
-.nav-link {
- text-decoration: none;
- color: #111827;
- font-weight: 500;
- position: relative;
-}
-
-.dark-theme .nav-link {
- color: #e5e7eb;
-}
-
-.nav-link:hover {
- color: #2563eb;
-}
-
-.nav-link.active::after {
- content: "";
- position: absolute;
- bottom: -6px;
- left: 0;
- width: 100%;
- height: 2px;
- background: #111827;
-}
-
-.dark-theme .nav-link.active::after {
- background: #f8fafc;
-}
-
-.header-right {
- margin-left: auto;
- display: flex;
- align-items: center;
-}
-
-:root {
- --header-height: 55px;
- --bg: #eefaf8;
- --card: rgba(255, 255, 255, 0.95);
- --muted: #7b8b8a;
- --accent-1: #5ab9ff;
- --accent-2: #4cb39f;
- --accent-grad: linear-gradient(90deg, #4cb39f, #5ab9ff);
- --success: #2fb06e;
- --glass: rgba(255, 255, 255, 0.85);
-}
-
-.dark-theme {
- --bg-overlay: rgba(0, 0, 0, 0.75);
- --glass-bg: rgba(0, 0, 0, 0.4);
- --text-color: #f3f3f3;
- --input-bg: rgba(11, 10, 10, 0.8);
- --button-bg: linear-gradient(90deg, #4444ff, #2266ff);
- --recent-bg: rgba(255, 255, 255, 0.1);
-}
-
-/* Preserve your dark theme variables too */
-body.dark-theme {
- --bg: #0f1720;
- --card: rgba(10, 14, 18, 0.92);
- --muted: #9aa7a6;
-}
-
-.page {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 1rem;
- padding: 2rem;
- min-height: 80vh;
-}
-
-.theme-toggle {
- background: transparent;
- border: none;
- cursor: pointer;
- padding: 8px;
- border-radius: 8px;
- font-weight: 700;
- background: var(--card);
-}
-
-/* Hero */
-.hero {
- width: 100%;
- max-width: 1100px;
- background: transparent;
- text-align: center;
- padding: 10px;
-}
-
-.hero h1 {
- margin: 10px 0 14px;
- font-size: 36px;
- line-height: 1.05;
- color: #000606;
-}
-
-.hero p {
- margin: var(--bg-overlay);
- color: var(--muted);
- max-width: 820px;
- margin-left: auto;
- margin-right: auto;
- color: #000606;
-}
-
-/* Main card & input */
-.card {
- width: 100%;
- max-width: 1100px;
- background: var(--card);
- border-radius: 14px;
- padding: 15px;
- box-shadow: 0 18px 50px rgba(8, 24, 24, 0.06);
-}
-
-.cta {
- min-width: 220px;
- padding: 14px 22px;
- border-radius: 12px;
- border: none;
- color: rgb(12, 1, 1);
- font-weight: 700;
- cursor: pointer;
- background: var(--accent-grad);
- box-shadow: 0 12px 28px rgba(77, 163, 185, 0.12);
-}
-
-.small-action {
- display: flex;
- align-items: center;
- gap: 8px;
- color: var(--muted);
- margin-top: 10px;
-}
-
-.result {
- margin-top: 26px;
- background: white;
- border-radius: 12px;
- padding: 20px;
- border: 1px solid rgba(22, 60, 55, 0.03);
- box-shadow: 0 8px 28px rgba(7, 20, 20, 0.03);
-}
-
-.result-header {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 12px;
-}
-
-.result-header .dot {
- width: 30px;
- height: 30px;
- background: var(--success);
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- color: white;
- font-weight: 700;
-}
-
-.short-actions {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 8px;
- padding: 10px 14px;
- border-radius: 12px;
- background: linear-gradient(180deg, rgba(75, 194, 176, 0.06), rgba(94, 207, 255, 0.04));
-}
-
-.short-box input {
- align-items: center;
- padding: 10px;
- font-size: 15px;
-}
-
-.btn-copy {
- border: none;
- padding: 10px 14px;
- border-radius: 8px;
- color: white;
- font-weight: 700;
- cursor: pointer;
-}
-
-.btn-share {
- background: #f2f5f5;
- border: none;
- padding: 10px 14px;
- border-radius: 8px;
- color: #0b2b2a;
- font-weight: 700;
- cursor: pointer;
- margin-left: 6px;
-}
-
-.meta-row {
- align-items: center;
- justify-content: center;
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 2px;
- padding: 16px;
- margin-top: 1px;
- align-items: top;
- color: black;
-}
-.result-body {
- margin-top: 30px;
-
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
-}
-
-.qr-block {
- text-align: center;
- padding-top: 8px;
-}
-
-.qr-block img {
- height: 15rem;
- align-items: center;
- aspect-ratio: 1;
- box-shadow: 0 10px 20px rgba(10, 20, 30, 0.06);
- outline: 2px solid green;
- outline-offset: 4px;
-}
-
-.download-qr {
- display: inline-block;
- margin-top: 12px;
- text-decoration: none;
- color: var(--accent-1);
- font-weight: 700;
-}
-
-.action-row {
- display: flex;
- justify-content: right;
- align-items: right;
-}
-
-.action-secondary {
- background: #f6fbfb;
- border: 1px solid rgba(0, 0, 0, 0.03);
- border-radius: 10px;
- cursor: pointer;
- font-weight: 700;
-}
-
-/* Force Generate QR to stay on one line */
-.qr-inline {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- white-space: nowrap;
-}
-
-.qr-inline input {
- margin: 0;
-}
-
-/* Responsive */
-@media (max-width: 880px) {
- .input-row {
- flex-direction: column;
- }
-
- .cta {
- width: 100%;
- }
-
- .meta-row {
- grid-template-columns: 1fr;
- }
-}
-.result-title {
- font-weight: 700;
- color: #0e34f6;
-}
-
-.dark-theme .result-title {
- color: #150cff;
-}
-
-footer {
- min-height: auto;
-}
-
-.app-footer {
- background: white;
- color: #e5e7eb;
- padding: 8px 10px;
- margin-top: auto;
- position: relative;
-}
-.dark-theme .app-footer {
- background: linear-gradient(180deg, #0b1220, #050b14);
-}
-
-.footer-container {
- margin: auto;
- display: flex;
- gap: 60px;
- justify-content: space-between;
- flex-wrap: wrap;
-}
-
-.footer-brand {
- max-width: 420px;
-}
-
-.footer-logo {
- width: 42px;
- height: 42px;
- background: linear-gradient(135deg, #2563eb, #5ab9ff);
- border-radius: 14px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 22px;
-}
-.dark-theme .footer-brand h3,
-.dark-theme .footer-brand p,
-.dark-theme .footer-col h4,
-.dark-theme .app-footer a,
-.dark-theme .footer-bottom {
- color: #f8fafc;
-}
-
-.footer-brand h3 {
- margin: 0;
- color: #000000;
- font-size: 22px;
- font-weight: 700;
-}
-
-.footer-brand p {
- margin-top: 8px;
- color: #000000;
- line-height: 1.6;
- font-size: 14px;
-}
-
-/* MAIN CONTENT */
-
-/* FOOTER */
-.app-footer {
- margin-top: auto;
-}
-
-/* GitHub button */
-.github-btn {
- display: inline-flex;
- align-items: center;
- gap: 2px;
- margin-top: 1px;
- padding: 10px 16px;
- border-radius: 8px;
- background: rgba(255, 255, 255, 0.06);
- color: #000000;
- text-decoration: none;
- font-weight: 600;
- transition: all 0.25s ease;
-}
-
-.github-btn:hover {
- background: black(11, 1, 1);
- transform: translateY(-2px);
-}
-
-.footer-links {
- display: flex;
- gap: 80px;
- flex-wrap: wrap;
-}
-
-.footer-col h4 {
- margin-bottom: 14px;
- font-size: 16px;
- color: #000000;
- font-weight: 700;
-}
-
-.footer-col a {
- display: block;
- text-decoration: none;
- color: #000000;
- margin-bottom: 10px;
- font-size: 14px;
- transition: color 0.2s ease;
-}
-
-.footer-col a:hover {
- text-decoration: underline;
-}
-
-/* Bottom */
-.footer-bottom {
- margin-top: 10px;
- border-top: 1px solid rgba(255, 255, 255, 0.153);
- padding-top: 8px;
- padding-bottom: 1px;
- text-align: center;
- font-size: 14px;
- color: #080808;
-}
-.footer-bottom a {
- color: #030000;
- font-weight: 600;
- text-decoration: none;
-}
-
-.footer-bottom a:hover {
- text-decoration: underline;
-}
-
-/* Responsive */
-@media (max-width: 768px) {
- .footer-container {
- flex-direction: column;
- gap: 40px;
- }
-
- .footer-links {
- gap: 40px;
- }
-}
-/* REMOVE white line above footer in dark mode */
-footer {
- margin-top: 0 !important;
-}
-.recent-table-wrapper {
- margin-top: 20px;
- width: 100%;
- overflow-x: auto;
-}
-
-.recent-table {
- width: 100%;
- border-collapse: collapse;
- border-radius: 12px;
- overflow: hidden;
-}
-
-.recent-table thead {
- background: rgb(0, 0, 0);
-}
-.recent-table th {
- color: rgb(0, 0, 0);
- padding: 8px 14px;
- text-align: left;
- font-size: 16px;
-}
-.short-code a {
- color: #2563eb;
- font-weight: 600;
- text-decoration: none;
-}
-
-.short-code a:hover {
- color: #1d4ed8;
- text-decoration: underline;
-}
-.recent-table td {
- color: rgb(34, 48, 77);
- padding: 10px 14px;
- text-align: left;
- font-size: 14px;
-}
-
-.created-time {
- font-size: 14px;
- color: #374151;
- white-space: nowrap;
-}
-
-.time-ago {
- color: #374151;
- font-size: 13px;
- margin-left: 2px;
-}
-.recent-table th {
- font-weight: 700;
-}
-
-.recent-table tbody tr,
-th {
- background: rgb(255, 255, 255);
- border-bottom: 1px solid rgb(0, 0, 0);
-}
-.dark-theme.recent-table tbody tr,
-td {
- background: rgba(255, 255, 255, 0.04);
- border-bottom: 1px solid rgb(0, 0, 0);
-}
-.recent-table tbody tr:hover {
- background: rgb(196, 196, 196);
-}
-
-/* Short code */
-.short-code {
- font-weight: 700;
-}
-
-.original-url {
- color: #22c55e;
- word-break: break-all;
-}
-
-/* Action buttons */
-.action-col {
- display: flex;
- gap: 10px;
-}
-
-.action-btn {
- width: 36px;
- height: 36px;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- text-decoration: none;
- font-size: 16px;
- transition: 0.2s ease;
-}
-
-.open-btn {
- background: #3b82f6;
- color: #fff;
-}
-
-.delete-btn {
- background: #ef4444;
- color: #fff;
-}
-
-.recent-table-wrapper {
- margin-bottom: 20px;
-}
-/* =========================
- Coming Soon Page
-========================= */
-
-.coming-soon-page {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 120px 20px 60px;
-}
-
-.coming-soon-card {
- max-width: 520px;
- width: 100%;
- background: var(--card);
- border-radius: 16px;
- padding: 50px 40px;
- text-align: center;
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.08);
-}
-
-.coming-icon {
- font-size: 48px;
- margin-bottom: 18px;
-}
-
-.coming-soon-card h1 {
- font-size: 34px;
- margin-bottom: 14px;
- color: #000;
-}
-
-.dark-theme .coming-soon-card h1 {
- color: #fff;
-}
-
-.coming-soon-card p {
- font-size: 15px;
- color: var(--muted);
- line-height: 1.6;
- margin-bottom: 28px;
-}
-
-.coming-btn {
- display: inline-block;
- padding: 12px 22px;
- border-radius: 10px;
- background: var(--accent-grad);
- color: #fff;
- font-weight: 700;
- text-decoration: none;
- transition: 0.25s ease;
-}
-
-.coming-btn:hover {
- transform: scale(1.05);
- box-shadow: 0 12px 28px rgba(77, 163, 185, 0.25);
-}
-.info-box {
- margin-bottom: 15px;
- padding: 10px;
- color: #0e34f6;
- border-radius: 8px;
- font-weight: 700;
-}
+html,
+body {
+ height: 100%;
+ margin: 0;
+ font-family: Arial;
+ padding: 0;
+ font-family: "Poppins", system-ui, Arial, sans-serif;
+ background: var(--bg);
+ background-size: cover;
+ background-position: center;
+ background-size: cover;
+ background-position: center;
+}
+
+input {
+ width: 70%;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ font-size: 16px;
+}
+
+.admin-box {
+ margin: 120px auto 60px;
+ /* space from header + footer */
+}
+
+.app-layout {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ margin-top: var(--header-height);
+}
+
+button {
+ padding: 8px;
+ margin: 5px;
+}
+
+.error-box {
+ margin-bottom: 15px;
+ padding: 10px;
+ color: #ff4d4d;
+ border-radius: 8px;
+ font-weight: 600;
+}
+
+.dark-theme h1 {
+ background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
+}
+
+.dark-theme p {
+ background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
+}
+
+.dark-theme {
+ --bg-overlay: rgba(0, 0, 0, 0.75);
+ --glass-bg: rgba(0, 0, 0, 0.4);
+ --text-color: #fff;
+ --input-bg: rgba(50, 50, 50, 0.8);
+ --input-text-color: #fff;
+}
+
+@keyframes pop {
+ 0% {
+ transform: scale(0.7);
+ opacity: 0;
+ }
+
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+/* INPUT CONTAINER */
+.input-field {
+ flex: 1 1 700px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ border-radius: 12px;
+ border: 2px solid rgb(6, 0, 0);
+ background: transparent;
+ /* IMPORTANT */
+ padding: 12px 12px;
+}
+
+.dark-theme .input-field {
+ border-color: #ffffff;
+}
+
+/* INPUT ITSELF */
+.input-field input[type="text"] {
+ width: 100%;
+ border: none;
+ outline: none;
+ background-color: transparent !important;
+ background-image: none !important;
+ box-shadow: none !important;
+ font-size: 23px;
+}
+
+.input-field input {
+ color: #000 !important;
+}
+
+.dark-theme .input-field input {
+ color: #fff !important;
+}
+
+.input-field input:-webkit-autofill,
+.input-field input:-webkit-autofill:hover,
+.input-field input:-webkit-autofill:focus,
+.input-field input:-webkit-autofill:active {
+ -webkit-box-shadow: 0 0 0 1000px transparent inset !important;
+ box-shadow: 0 0 0 1000px transparent inset !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ transition: background-color 9999s ease-in-out 0s;
+}
+
+.input-field input:-webkit-autofill {
+ -webkit-text-fill-color: #000 !important;
+}
+
+.dark-theme .input-field input:-webkit-autofill {
+ -webkit-text-fill-color: #fff !important;
+}
+
+.input-field input::selection,
+.input-field input::-moz-selection {
+ background: transparent;
+ color: inherit;
+}
+
+.short-code {
+ color: #0a0000;
+ /* blue like links */
+ font-weight: 700;
+}
+
+.app-header {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 97%;
+ height: 55px;
+ background: white;
+ display: flex;
+ align-items: center;
+ padding: 0 28px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
+ z-index: 1000;
+}
+
+/* Dark mode */
+.dark-theme .app-header {
+ background: linear-gradient(180deg, #0b1220, #050b14);
+}
+
+footer {
+ margin-top: 0;
+}
+
+body.dark-theme,
+body.dark-theme .page,
+body.dark-theme main,
+body.dark-theme section {
+ background: #0f1720 !important;
+}
+
+.header-left {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.app-logo {
+ width: 36px;
+ height: 36px;
+ background: linear-gradient(135deg, #2563eb, #5ab9ff);
+ color: white;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+}
+
+.app-name {
+ font-size: 20px;
+ font-weight: 700;
+ color: #111827;
+}
+
+.dark-theme .app-name {
+ color: #f8fafc;
+}
+
+.header-nav {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ gap: 26px;
+}
+
+.nav-link {
+ text-decoration: none;
+ color: #111827;
+ font-weight: 500;
+ position: relative;
+}
+
+.dark-theme .nav-link {
+ color: #e5e7eb;
+}
+
+.nav-link:hover {
+ color: #2563eb;
+}
+
+.nav-link.active::after {
+ content: "";
+ position: absolute;
+ bottom: -6px;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ background: #111827;
+}
+
+.dark-theme .nav-link.active::after {
+ background: #f8fafc;
+}
+
+.header-right {
+ margin-left: auto;
+ display: flex;
+ align-items: center;
+}
+
+/*:root {
+ --header-height: 55px;
+ --bg: #eefaf8;
+ --card: rgba(255, 255, 255, 0.95);
+ --muted: #7b8b8a;
+ --accent-1: #5ab9ff;
+ --accent-2: #4cb39f;
+ --accent-grad: linear-gradient(90deg, #4cb39f, #5ab9ff);
+ --success: #2fb06e;
+ --glass: rgba(255, 255, 255, 0.85);
+}*/
+
+:root {
+ /* Background */
+ --bg: #eefaf8;
+ --card: rgba(255, 255, 255, 0.85);
+
+ /* Text */
+ --text-color: #1f2937;
+ --text-muted: #6b7280;
+
+ /* Borders */
+ --glass-border: rgba(0, 0, 0, 0.08);
+
+ /* Accent */
+ --accent-1: #5ab9ff;
+ --accent-2: #4cb39f;
+
+ /* Shadow */
+ --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.12);
+}
+
+.dark-theme {
+ --bg-overlay: rgba(0, 0, 0, 0.75);
+ --glass-bg: rgba(0, 0, 0, 0.4);
+ --text-color: #f3f3f3;
+ --input-bg: rgba(11, 10, 10, 0.8);
+ --button-bg: linear-gradient(90deg, #4444ff, #2266ff);
+ --recent-bg: rgba(255, 255, 255, 0.1);
+}
+
+/* Preserve your dark theme variables too */
+body.dark-theme {
+ --bg: #0f1720;
+ --card: rgba(20, 25, 30, 0.75);
+
+ --text-color: #e5e7eb;
+ --text-muted: #9aa7a6;
+
+ --glass-border: rgba(255, 255, 255, 0.08);
+
+ --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
+}
+
+.page {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ padding: 2rem;
+ min-height: 80vh;
+}
+
+.theme-toggle {
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ padding: 8px;
+ border-radius: 8px;
+ font-weight: 700;
+ background: var(--card);
+}
+
+/* Hero */
+.hero {
+ width: 100%;
+ max-width: 1100px;
+ background: transparent;
+ text-align: center;
+ padding: 10px;
+}
+
+.hero h1 {
+ margin: 10px 0 14px;
+ font-size: 36px;
+ line-height: 1.05;
+ color: #000606;
+}
+
+.hero p {
+ margin: var(--bg-overlay);
+ color: var(--muted);
+ max-width: 820px;
+ margin-left: auto;
+ margin-right: auto;
+ color: #000606;
+}
+
+/* Main card & input */
+.card {
+ width: 100%;
+ max-width: 1100px;
+ background: var(--card);
+ border-radius: 14px;
+ padding: 15px;
+ box-shadow: 0 18px 50px rgba(8, 24, 24, 0.06);
+}
+
+.cta {
+ min-width: 220px;
+ padding: 14px 22px;
+ border-radius: 12px;
+ border: none;
+ color: rgb(12, 1, 1);
+ font-weight: 700;
+ cursor: pointer;
+ background: var(--accent-grad);
+ box-shadow: 0 12px 28px rgba(77, 163, 185, 0.12);
+}
+
+.small-action {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ color: var(--muted);
+ margin-top: 10px;
+}
+
+.result {
+ margin-top: 26px;
+ background: white;
+ border-radius: 12px;
+ padding: 20px;
+ border: 1px solid rgba(22, 60, 55, 0.03);
+ box-shadow: 0 8px 28px rgba(7, 20, 20, 0.03);
+}
+
+.result-header {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 12px;
+}
+
+.result-header .dot {
+ width: 30px;
+ height: 30px;
+ background: var(--success);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: white;
+ font-weight: 700;
+}
+
+.short-actions {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 14px;
+ border-radius: 12px;
+ background: linear-gradient(180deg, rgba(75, 194, 176, 0.06), rgba(94, 207, 255, 0.04));
+}
+
+.short-box input {
+ align-items: center;
+ padding: 10px;
+ font-size: 15px;
+}
+
+.btn-copy {
+ border: none;
+ padding: 10px 14px;
+ border-radius: 8px;
+ color: white;
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.btn-share {
+ background: #f2f5f5;
+ border: none;
+ padding: 10px 14px;
+ border-radius: 8px;
+ color: #0b2b2a;
+ font-weight: 700;
+ cursor: pointer;
+ margin-left: 6px;
+}
+
+.meta-row {
+ align-items: center;
+ justify-content: center;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2px;
+ padding: 16px;
+ margin-top: 1px;
+ align-items: top;
+ color: black;
+}
+
+.result-body {
+ margin-top: 30px;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+}
+
+.qr-block {
+ text-align: center;
+ padding-top: 8px;
+}
+
+.qr-block img {
+ height: 15rem;
+ align-items: center;
+ aspect-ratio: 1;
+ box-shadow: 0 10px 20px rgba(10, 20, 30, 0.06);
+ outline: 2px solid green;
+ outline-offset: 4px;
+}
+
+.download-qr {
+ display: inline-block;
+ margin-top: 12px;
+ text-decoration: none;
+ color: var(--accent-1);
+ font-weight: 700;
+}
+
+.action-row {
+ display: flex;
+ justify-content: right;
+ align-items: right;
+}
+
+.action-secondary {
+ background: #f6fbfb;
+ border: 1px solid rgba(0, 0, 0, 0.03);
+ border-radius: 10px;
+ cursor: pointer;
+ font-weight: 700;
+}
+
+/* Force Generate QR to stay on one line */
+.qr-inline {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ white-space: nowrap;
+}
+
+.qr-inline input {
+ margin: 0;
+}
+
+/* Responsive */
+@media (max-width: 880px) {
+ .input-row {
+ flex-direction: column;
+ }
+
+ .cta {
+ width: 100%;
+ }
+
+ .meta-row {
+ grid-template-columns: 1fr;
+ }
+}
+
+.result-title {
+ font-weight: 700;
+ color: #0e34f6;
+}
+
+.dark-theme .result-title {
+ color: #150cff;
+}
+
+footer {
+ min-height: auto;
+}
+
+.app-footer {
+ background: white;
+ color: #e5e7eb;
+ padding: 8px 10px;
+ margin-top: auto;
+ position: relative;
+}
+
+.dark-theme .app-footer {
+ background: linear-gradient(180deg, #0b1220, #050b14);
+}
+
+.footer-container {
+ margin: auto;
+ display: flex;
+ gap: 60px;
+ justify-content: space-between;
+ flex-wrap: wrap;
+}
+
+.footer-brand {
+ max-width: 420px;
+}
+
+.footer-logo {
+ width: 42px;
+ height: 42px;
+ background: linear-gradient(135deg, #2563eb, #5ab9ff);
+ border-radius: 14px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 22px;
+}
+
+.dark-theme .footer-brand h3,
+.dark-theme .footer-brand p,
+.dark-theme .footer-col h4,
+.dark-theme .app-footer a,
+.dark-theme .footer-bottom {
+ color: #f8fafc;
+}
+
+.footer-brand h3 {
+ margin: 0;
+ color: #000000;
+ font-size: 22px;
+ font-weight: 700;
+}
+
+.footer-brand p {
+ margin-top: 8px;
+ color: #000000;
+ line-height: 1.6;
+ font-size: 14px;
+}
+
+/* MAIN CONTENT */
+
+/* FOOTER */
+.app-footer {
+ margin-top: auto;
+}
+
+/* GitHub button */
+.github-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 2px;
+ margin-top: 1px;
+ padding: 10px 16px;
+ border-radius: 8px;
+ background: rgba(255, 255, 255, 0.06);
+ color: #000000;
+ text-decoration: none;
+ font-weight: 600;
+ transition: all 0.25s ease;
+}
+
+.github-btn:hover {
+ background: black(11, 1, 1);
+ transform: translateY(-2px);
+}
+
+.footer-links {
+ display: flex;
+ gap: 80px;
+ flex-wrap: wrap;
+}
+
+.footer-col h4 {
+ margin-bottom: 14px;
+ font-size: 16px;
+ color: #000000;
+ font-weight: 700;
+}
+
+.footer-col a {
+ display: block;
+ text-decoration: none;
+ color: #000000;
+ margin-bottom: 10px;
+ font-size: 14px;
+ transition: color 0.2s ease;
+}
+
+.footer-col a:hover {
+ text-decoration: underline;
+}
+
+/* Bottom */
+.footer-bottom {
+ margin-top: 10px;
+ border-top: 1px solid rgba(255, 255, 255, 0.153);
+ padding-top: 8px;
+ padding-bottom: 1px;
+ text-align: center;
+ font-size: 14px;
+ color: #080808;
+}
+
+.footer-bottom a {
+ color: #030000;
+ font-weight: 600;
+ text-decoration: none;
+}
+
+.footer-bottom a:hover {
+ text-decoration: underline;
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .footer-container {
+ flex-direction: column;
+ gap: 40px;
+ }
+
+ .footer-links {
+ gap: 40px;
+ }
+}
+
+/* REMOVE white line above footer in dark mode */
+footer {
+ margin-top: 0 !important;
+}
+
+
+/*===============================
+ MODERN GLASS RECENT TABLE
+================================ */
+
+.recent-page-container {
+ width: 100%;
+ max-width: 1100px;
+ margin: 30px auto;
+ padding: 28px;
+
+ background: var(--card);
+ backdrop-filter: blur(20px);
+
+ border: 1px solid var(--glass-border);
+ border-radius: 20px;
+
+ box-shadow: var(--card-shadow);
+ color: var(--text-color);
+
+ transition: background 0.3s ease, border 0.3s ease;
+}
+
+.recent-table-wrapper {
+ margin-top: 20px;
+ width: 100%;
+ overflow-x: auto;
+}
+
+/* Table */
+.recent-table {
+ width: 100%;
+ border-collapse: collapse;
+ border-radius: 12px;
+ overflow: hidden;
+}
+
+/* Header */
+.recent-table thead {
+ background: var(--glass);
+}
+
+.recent-table th {
+ padding: 8px 14px;
+ text-align: left;
+ font-size: 13px;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ font-weight: 700;
+ color: var(--muted);
+ border-bottom: 1px solid var(--glass-border);
+}
+
+/* Body cells */
+.recent-table td {
+ padding: 14px;
+ font-size: 14px;
+ color: var(--text-primary);
+ border-bottom: 1px solid var(--glass-border);
+ transition: 0.25s ease;
+}
+
+/* Row hover */
+.recent-table tbody tr:hover {
+ background: rgba(255, 255, 255, 0.05);
+}
+
+/* Short link */
+.short-code a {
+ color: var(--accent);
+ font-weight: 700;
+ text-decoration: none;
+}
+
+.short-code a:hover {
+ color: var(--accent-2);
+ text-decoration: underline;
+}
+
+/* Original URL */
+.original-url {
+ word-break: break-all;
+}
+
+.original-url a {
+ color: var(--text-secondary);
+ text-decoration: none;
+}
+
+.original-url a:hover {
+ color: var(--accent);
+}
+
+/* Created time */
+.created-time {
+ font-size: 13px;
+ color: var(--muted);
+ white-space: nowrap;
+}
+
+/* Visit count highlight */
+.recent-table td:nth-child(5) {
+ font-weight: 700;
+ color: var(--accent-2);
+}
+
+/* Dark mode adjustments */
+.dark-theme .recent-table th,
+.dark-theme .recent-table td {
+ color: #e5e7eb;
+ border-bottom: 1px solid var(--glass-border);
+}
+
+/* Action buttons */
+.action-col {
+ display: flex;
+ gap: 10px;
+}
+
+.action-btn {
+ width: 36px;
+ height: 36px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-decoration: none;
+ font-size: 16px;
+ transition: 0.2s ease;
+}
+
+.open-btn {
+ background: #3b82f6;
+ color: #fff;
+}
+
+.delete-btn {
+ background: #ef4444;
+ color: #fff;
+}
+
+.recent-table-wrapper {
+ margin-bottom: 20px;
+}
+
+
+/* =========================
+ Coming Soon Page
+========================= */
+
+.coming-soon-page {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 120px 20px 60px;
+}
+
+.coming-soon-card {
+ max-width: 520px;
+ width: 100%;
+ background: var(--card);
+ border-radius: 16px;
+ padding: 50px 40px;
+ text-align: center;
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.08);
+}
+
+.coming-icon {
+ font-size: 48px;
+ margin-bottom: 18px;
+}
+
+.coming-soon-card h1 {
+ font-size: 34px;
+ margin-bottom: 14px;
+ color: #000;
+}
+
+.dark-theme .coming-soon-card h1 {
+ color: #fff;
+}
+
+.coming-soon-card p {
+ font-size: 15px;
+ color: var(--muted);
+ line-height: 1.6;
+ margin-bottom: 28px;
+}
+
+.coming-btn {
+ display: inline-block;
+ padding: 12px 22px;
+ border-radius: 10px;
+ background: var(--accent-grad);
+ color: #fff;
+ font-weight: 700;
+ text-decoration: none;
+ transition: 0.25s ease;
+}
+
+.coming-btn:hover {
+ transform: scale(1.05);
+ box-shadow: 0 12px 28px rgba(77, 163, 185, 0.25);
+}
+
+.info-box {
+ margin-bottom: 15px;
+ padding: 10px;
+ color: #0e34f6;
+ border-radius: 8px;
+ font-weight: 700;
+}
\ No newline at end of file
diff --git a/app/templates/recent.html b/app/templates/recent.html
index 26c5d69..d20b35a 100644
--- a/app/templates/recent.html
+++ b/app/templates/recent.html
@@ -10,7 +10,7 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
Recent Shortened URLs
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/templates/recent.html b/app/templates/recent.html
index d20b35a..d25afeb 100644
--- a/app/templates/recent.html
+++ b/app/templates/recent.html
@@ -1,225 +1,61 @@
-
-
-
-