Skip to content

Commit 8095fe3

Browse files
Merge pull request #44 from recursivezero/main
πŸš€ Release: 2026-03-14
2 parents bda137e + 8377fa7 commit 8095fe3

File tree

11 files changed

+176
-58
lines changed

11 files changed

+176
-58
lines changed

β€Ž.gitignoreβ€Ž

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ logs/
3939
log/
4040

4141

42-
.vscode/
4342
.idea/
4443
*.swp
4544
*.swo

β€Ž.vscode/dictionaries/project-words.txtβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
APIHTTP
12
appleboy
23
projectx
34
RZRO

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ All notable changes to this repository will be documented in this file.
2222

2323
- Added Database connection retry logic
2424

25-
## [1.1.1] THu, Mar 12, 2026
25+
## [1.1.1] Thu, Mar 12, 2026
2626

2727
- Added Memory Cache
2828
- Redesign Page
29+
30+
## [1.1.2] Sat, Mar 14, 2026
31+
32+
- Mobile responsiveness
33+
- Added Contact us Page

β€Žapp/routes.pyβ€Ž

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,52 @@
11
import os
22
from datetime import datetime, timezone
33
from typing import Optional
4-
from app.utils.cache import list_cache_clean, clear_cache
4+
55
from fastapi import (
66
APIRouter,
7-
Form,
8-
Request,
9-
status,
10-
HTTPException,
117
BackgroundTasks,
8+
Form,
129
Header,
10+
HTTPException,
1311
Query,
12+
Request,
13+
status,
1414
)
1515
from fastapi.responses import (
1616
HTMLResponse,
17+
JSONResponse,
1718
PlainTextResponse,
1819
RedirectResponse,
19-
JSONResponse,
2020
)
2121
from fastapi.templating import Jinja2Templates
2222
from pydantic import BaseModel, Field
2323

24-
2524
from app import __version__
2625
from app.utils import db
2726
from app.utils.cache import (
27+
clear_cache,
2828
get_from_cache,
2929
get_recent_from_cache,
3030
get_short_from_cache,
31-
set_cache_pair,
3231
increment_visit_cache,
33-
url_cache,
32+
list_cache_clean,
3433
remove_cache_key,
3534
rev_cache,
35+
set_cache_pair,
36+
url_cache,
3637
)
3738
from app.utils.config import (
39+
CACHE_PURGE_TOKEN,
3840
DOMAIN,
3941
MAX_RECENT_URLS,
40-
CACHE_PURGE_TOKEN,
4142
QR_DIR,
4243
)
4344
from app.utils.helper import (
44-
generate_code,
45-
sanitize_url,
46-
is_valid_url,
4745
authorize_url,
4846
format_date,
47+
generate_code,
48+
is_valid_url,
49+
sanitize_url,
4950
)
5051
from app.utils.qr import generate_qr_with_logo
5152

@@ -112,12 +113,14 @@ async def create_short_url(
112113

113114
if not original_url or not is_valid_url(original_url): # validate the URL
114115
session["error"] = "Please enter a valid URL."
116+
session["original_url"] = original_url # preserve user input
115117
return RedirectResponse("/", status_code=status.HTTP_303_SEE_OTHER)
116118

117119
if not authorize_url(
118120
original_url
119121
): # authorize the URL based on whitelist/blacklist
120122
session["error"] = "This domain is not allowed."
123+
session["original_url"] = original_url # preserve user input
121124
return RedirectResponse("/", status_code=status.HTTP_303_SEE_OTHER)
122125

123126
short_code: Optional[str] = get_short_from_cache(original_url)
@@ -150,6 +153,11 @@ async def create_short_url(
150153
return RedirectResponse("/", status_code=status.HTTP_303_SEE_OTHER)
151154

152155

156+
@ui_router.get("/contact", response_class=HTMLResponse)
157+
async def contact(request: Request):
158+
return templates.TemplateResponse("contact.html", {"request": request})
159+
160+
153161
@ui_router.get("/history", response_class=HTMLResponse)
154162
async def recent_urls(request: Request):
155163
recent_urls_list = db.get_recent_urls(MAX_RECENT_URLS) or get_recent_from_cache(

β€Žapp/static/css/tiny.cssβ€Ž

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
html,
2-
body {
3-
height: 100%;
4-
margin: 0;
5-
font-family: Arial;
6-
padding: 0;
7-
font-family: "Poppins", system-ui, Arial, sans-serif;
8-
background: var(--bg);
9-
background-size: cover;
10-
background-position: center;
11-
background-size: cover;
12-
background-position: center;
1+
*,
2+
*::before,
3+
*::after {
4+
box-sizing: border-box;
135
}
146

157
:root {
@@ -27,6 +19,11 @@ body {
2719
font-family: "Inter", system-ui, sans-serif;
2820
margin: 0;
2921
overflow-x: hidden;
22+
background-image: radial-gradient(circle at 50% -20%, #1e1e2e 0%, transparent 50%);
23+
}
24+
25+
a {
26+
color: var(--accent);
3027
}
3128

3229
body.light-theme {
@@ -47,6 +44,16 @@ body.light-theme {
4744
min-height: 100vh;
4845
}
4946

47+
.main-layout {
48+
max-width: 870px;
49+
margin: 0 auto;
50+
padding: 6rem 1rem 4rem;
51+
display: flex;
52+
flex-direction: column;
53+
gap: 2rem;
54+
flex: 1;
55+
}
56+
5057
.main-layout {
5158
width: 90%;
5259
margin: 2rem auto;
@@ -63,7 +70,6 @@ body.light-theme {
6370
justify-content: space-between;
6471
padding: 0 10px;
6572
box-sizing: border-box;
66-
6773
background: var(--glass);
6874
border-bottom: 1px solid var(--glass-border);
6975
z-index: 1000;
@@ -103,7 +109,9 @@ body.light-theme .app-header {
103109
.header-nav {
104110
display: flex;
105111
gap: 26px;
106-
margin: 0 auto;
112+
flex-wrap: wrap;
113+
white-space: nowrap;
114+
flex-shrink: 1;
107115
}
108116

109117
.nav-link,
@@ -175,9 +183,49 @@ body.dark-theme .app-header {
175183
color: var(--accent);
176184
}
177185

186+
/* hamburger hidden on desktop */
187+
188+
.hamburger {
189+
display: none;
190+
font-size: 22px;
191+
background: transparent;
192+
border: none;
193+
color: var(--text-primary);
194+
cursor: pointer;
195+
}
196+
178197
@media (max-width: 600px) {
179-
.logo {
180-
font-size: 1.2rem;
198+
.app-logo {
199+
transform: scale(0.9);
200+
}
201+
202+
.app-name {
203+
font-size: 1.1rem;
204+
}
205+
}
206+
207+
@media (max-width: 700px) {
208+
.hamburger {
209+
display: block;
210+
}
211+
212+
.header-nav {
213+
display: none;
214+
position: fixed;
215+
top: 55px;
216+
left: 0;
217+
right: 0;
218+
width: 100%;
219+
flex-direction: column;
220+
background: var(--bg);
221+
padding: 20px;
222+
display: none;
223+
gap: 16px;
224+
border-bottom: 1px solid var(--glass-border);
225+
}
226+
227+
.header-nav.open {
228+
display: flex;
181229
}
182230
}
183231

@@ -275,6 +323,10 @@ body.dark-theme .app-header {
275323
gap: 1.5rem;
276324
}
277325

326+
.short-url {
327+
max-width: 100%;
328+
}
329+
278330
.qr-image {
279331
width: 80px;
280332
height: 80px;
@@ -295,6 +347,8 @@ body.dark-theme .app-header {
295347
font-weight: 700;
296348
color: var(--text-primary);
297349
text-decoration: none;
350+
word-break: break-all;
351+
overflow-wrap: anywhere;
298352
}
299353

300354
.result-actions {
@@ -388,6 +442,21 @@ body.dark-theme .app-header {
388442
font-weight: 700;
389443
}
390444

445+
@media (max-width: 768px) {
446+
.input-wrapper {
447+
flex-direction: column;
448+
}
449+
450+
.btn-primary {
451+
width: 100%;
452+
}
453+
454+
.scroll-container {
455+
padding-left: 12px;
456+
padding-right: 12px;
457+
}
458+
}
459+
391460
/* ===============================
392461
MODERN GLASS RECENT TABLE
393462
================================= */
@@ -402,6 +471,7 @@ body.dark-theme .app-header {
402471
.recent-table-wrapper {
403472
width: 100%;
404473
overflow-x: auto;
474+
-webkit-overflow-scrolling: touch;
405475
}
406476

407477
/* ===============================
@@ -414,7 +484,7 @@ body.dark-theme .app-header {
414484
border-radius: 12px;
415485
overflow: hidden;
416486
table-layout: fixed;
417-
min-width: 800px;
487+
min-width: 720px;
418488
}
419489

420490
.recent-table thead {
@@ -590,10 +660,7 @@ footer.big-footer {
590660
background: var(--bg);
591661
border-top: 1px solid var(--glass-border);
592662
padding: 4rem 1rem 2rem;
593-
margin-top: 4rem;
594-
position: fixed;
595-
bottom: 0;
596-
width: 100%;
663+
margin-top: auto;
597664
}
598665

599666
.footer-grid {
@@ -777,3 +844,18 @@ body.light-theme .history-link {
777844
.history-link:hover {
778845
opacity: 0.7;
779846
}
847+
848+
.contact-info {
849+
max-width: 600px;
850+
margin: 0 auto;
851+
background: var(--glass);
852+
border: 1px solid var(--glass-border);
853+
border-radius: 1rem;
854+
padding: 2rem;
855+
list-style-type: none;
856+
& li {
857+
margin-bottom: 1rem;
858+
font-size: 1.1rem;
859+
color: var(--text-primary);
860+
}
861+
}

β€Žapp/templates/404.htmlβ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<html>
44

55
<head>
6-
<title>Page Not Found</title>
6+
<title>rzro.link: Page Not Found</title>
77
<style>
88
body {
99
margin: 0;
@@ -41,8 +41,8 @@
4141
<h1>🚫 Page not found</h1>
4242
<p>The page you are looking for does not exist.</p>
4343

44-
<a href="/" onclick="history.back(); return false;">
45-
← Go Back
44+
<a href="/">
45+
← Go Home
4646
</a>
4747
</div>
4848
</body>

β€Žapp/templates/contact.htmlβ€Ž

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% extends "layout.html" %} {% block content %}
2+
<div class="main-layout">
3+
<div class="contact-card">
4+
<h1>Contact Us</h1>
5+
<p>If you have any questions, feedback, or need assistance, feel free to reach out to us!</p>
6+
<ul class="contact-info">
7+
<li><strong>Email:</strong> <a href="mailto:hello@recursivezero.com">hello@recursivezero.com</a></li>
8+
<li><strong>Twitter:</strong> <a href="https://twitter.com/recursivezero" target="_blank">@recursivezero</a></li>
9+
<li><strong>GitHub:</strong> <a href="https://github.com/recursivezero/tiny/issues" target="_blank">GitHub
10+
Issues</a></li>
11+
</ul>
12+
</div>
13+
</div>
14+
{% endblock %}

β€Žapp/templates/footer.htmlβ€Ž

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ <h3>πŸ”— RZRO.link</h3>
66
<div class="footer-col">
77
<h4>Product</h4>
88
<ul>
9-
<li><a href="cache/list">CACHE URLs</a></li>
109
<li><a href="#">API Documentation</a></li>
1110
<li><a href="#">Custom Branded Links</a></li>
1211
<li><a href="#">QR Code Engine</a></li>
@@ -15,7 +14,6 @@ <h4>Product</h4>
1514
<div class="footer-col">
1615
<h4>Support</h4>
1716
<ul>
18-
<li><a href="/docs"> UI docs</a></li>
1917
<li><a href="#">Help Center</a></li>
2018
<li><a href="#">System Status</a></li>
2119
<li><a href="#">Contact Us</a></li>

0 commit comments

Comments
Β (0)