test version fetcher
All checks were successful
Deploy to Production / deploy (push) Successful in 6s

This commit is contained in:
Илья Глазунов 2025-12-07 22:50:29 +03:00
parent aeccf99ad3
commit 0dca4e8ddc
3 changed files with 397 additions and 4 deletions

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pyserve - Documentation</title>
<link rel="stylesheet" href="style.css">
<script src="scripts/version-fetcher.js" defer></script>
</head>
<body>
<div id="container">
@ -13,7 +14,8 @@
<div class="tagline">python application orchestrator</div>
</div>
<div id="content">
<div id="main-wrapper">
<div id="content">
<h2>About</h2>
<p>
pyserve is a Python application orchestrator and HTTP server.
@ -102,7 +104,7 @@
</ul>
<h2>Version</h2>
<p>Current version: <strong>0.9.10</strong></p>
<p>Current version: <strong id="current-version">0.9.10</strong></p>
<h2>Requirements</h2>
<ul class="indent">
@ -110,6 +112,43 @@
</ul>
</div>
<!-- <aside id="sidebar">
<div class="partner-block">
<h3>Sponsors & Partners</h3>
<div class="partner-card">
<div class="partner-icon">🚀</div>
<h4>Cloud Hosting</h4>
<p>Deploy your pyserve applications with enterprise-grade reliability.</p>
<a href="#" class="partner-link">Learn More →</a>
</div>
<div class="partner-card">
<div class="partner-icon">📊</div>
<h4>Monitoring</h4>
<p>Real-time monitoring and analytics for your production apps.</p>
<a href="#" class="partner-link">Get Started →</a>
</div>
<div class="partner-card">
<div class="partner-icon">🔐</div>
<h4>Security</h4>
<p>Advanced security scanning and vulnerability detection.</p>
<a href="#" class="partner-link">Secure Now →</a>
</div>
<div class="community-block">
<h4>Community</h4>
<ul class="community-links">
<li><a href="https://git.pyserve.org">Git Repository</a></li>
<li><a href="#">Discord Server</a></li>
<li><a href="#">Stack Overflow</a></li>
</ul>
</div>
</div>
</aside> -->
</div>
<div id="footer">
<p>pyserve &copy; 2024-2025 | MIT License</p>
</div>

149
scripts/version-fetcher.js Normal file
View File

@ -0,0 +1,149 @@
/**
* Version Fetcher - Automatically fetches and displays latest pyserveX version
* from Gitea releases page
*/
(function() {
'use strict';
const RELEASES_URL = 'https://git.pyserve.org/Shifty/pyserveX/releases/latest';
const VERSION_ELEMENT_ID = 'current-version';
const CACHE_KEY = 'pyserve_version_cache';
const CACHE_DURATION = 3600000; // 1 hour
const FALLBACK_VERSION = 'offline';
async function fetchLatestVersion() {
try {
const response = await fetch(RELEASES_URL, {
method: 'GET',
mode: 'cors',
headers: {
'Accept': 'text/html'
}
});
if (!response.ok) {
console.warn(`Failed to fetch: ${response.status}`);
return null;
}
const html = await response.text();
const patterns = [
/<title>PyServeX\s+v([\d.]+)/i,
/releases\/tag\/v([\d.]+)/,
/aria-label="PyServeX\s+v([\d.]+)/i,
/<h4[^>]*>.*?v([\d.]+).*?<\/h4>/i
];
for (const pattern of patterns) {
const match = html.match(pattern);
if (match && match[1]) {
console.log(`✓ Version found: ${match[1]}`);
return match[1];
}
}
console.warn('Version not found in HTML');
return null;
} catch (error) {
console.warn('Fetch error:', error.message);
return null;
}
}
function getCachedVersion() {
try {
const cached = localStorage.getItem(CACHE_KEY);
if (!cached) return null;
const data = JSON.parse(cached);
const now = Date.now();
if (now - data.timestamp < CACHE_DURATION) {
return data.version;
}
localStorage.removeItem(CACHE_KEY);
return null;
} catch (error) {
console.error('Cache read error:', error);
return null;
}
}
function cacheVersion(version) {
try {
const data = {
version: version,
timestamp: Date.now()
};
localStorage.setItem(CACHE_KEY, JSON.stringify(data));
} catch (error) {
console.error('Cache write error:', error);
}
}
function updateVersionDisplay(version) {
const element = document.getElementById(VERSION_ELEMENT_ID);
if (!element) {
console.warn('Version element not found');
return;
}
const versionLink = document.createElement('a');
versionLink.href = 'https://git.pyserve.org/Shifty/pyserveX/releases/tag/v' + version;
versionLink.textContent = version;
versionLink.target = '_blank';
versionLink.rel = 'noopener noreferrer';
versionLink.className = 'version-link';
element.innerHTML = '';
element.appendChild(versionLink);
const badge = document.createElement('span');
badge.textContent = 'latest';
badge.className = 'version-badge';
badge.title = 'Fetched from Git repository';
element.appendChild(document.createTextNode(' '));
element.appendChild(badge);
element.style.opacity = '1';
}
function showLoadingState() {
const element = document.getElementById(VERSION_ELEMENT_ID);
if (element) {
element.style.opacity = '0.6';
}
}
async function init() {
showLoadingState();
const cachedVersion = getCachedVersion();
if (cachedVersion) {
updateVersionDisplay(cachedVersion);
}
const latestVersion = await fetchLatestVersion();
if (latestVersion) {
cacheVersion(latestVersion);
updateVersionDisplay(latestVersion);
} else if (!cachedVersion) {
const element = document.getElementById(VERSION_ELEMENT_ID);
if (element) {
element.textContent = FALLBACK_VERSION;
element.style.opacity = '1';
element.style.color = '#c9c9c9';
element.title = 'Version fetch failed (CORS or network issue)';
}
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();

209
style.css
View File

@ -13,7 +13,7 @@ body {
}
#container {
max-width: 800px;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
@ -38,7 +38,7 @@ body {
}
#content {
margin-bottom: 30px;
margin-bottom: 0;
}
h2 {
@ -235,3 +235,208 @@ dd {
color: #666;
font-style: italic;
}
/* Main wrapper for two-column layout */
#main-wrapper {
display: flex;
gap: 30px;
align-items: flex-start;
}
#content {
flex: 1;
min-width: 0;
}
/* Sidebar */
#sidebar {
width: 300px;
flex-shrink: 0;
}
.partner-block {
position: sticky;
top: 20px;
background: #0d0d0d;
border: 1px solid #333;
border-radius: 8px;
padding: 20px;
}
.partner-block h3 {
color: #3cb371;
font-size: 16px;
margin: 0 0 15px 0;
padding-bottom: 10px;
border-bottom: 2px solid #2e8b57;
}
.partner-card {
background: #1a1a1a;
border: 1px solid #2a2a2a;
border-radius: 6px;
padding: 15px;
margin-bottom: 15px;
transition: all 0.3s ease;
}
.partner-card:hover {
border-color: #3cb371;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(60, 179, 113, 0.1);
}
.partner-icon {
font-size: 32px;
margin-bottom: 10px;
}
.partner-card h4 {
color: #e0e0e0;
font-size: 14px;
font-weight: bold;
margin: 0 0 8px 0;
}
.partner-card p {
color: #999;
font-size: 12px;
line-height: 1.6;
margin: 0 0 10px 0;
}
.partner-link {
display: inline-block;
color: #5fba7d;
font-size: 12px;
font-weight: bold;
text-decoration: none;
transition: color 0.2s ease;
}
.partner-link:hover {
color: #7ccd9a;
}
.community-block {
background: #1a2a1a;
border: 1px solid #2e4a2e;
border-radius: 6px;
padding: 15px;
margin-top: 15px;
}
.community-block h4 {
color: #3cb371;
font-size: 14px;
font-weight: bold;
margin: 0 0 10px 0;
}
.community-links {
list-style: none;
margin: 0;
padding: 0;
}
.community-links li {
padding: 5px 0;
}
.community-links li:before {
content: "► ";
color: #2e8b57;
font-size: 10px;
margin-right: 5px;
}
.community-links a {
color: #5fba7d;
font-size: 12px;
text-decoration: none;
}
.community-links a:hover {
color: #7ccd9a;
text-decoration: underline;
}
/* Responsive design */
@media (max-width: 1024px) {
#container {
max-width: 900px;
}
#sidebar {
width: 250px;
}
}
@media (max-width: 768px) {
#main-wrapper {
flex-direction: column;
}
#sidebar {
width: 100%;
margin-top: 30px;
}
.partner-block {
position: static;
}
/* On mobile, show partner cards in a more compact grid */
.partner-card {
margin-bottom: 12px;
}
}
@media (max-width: 480px) {
#container {
padding: 15px;
}
.partner-block {
padding: 15px;
}
.partner-card {
padding: 12px;
}
.partner-icon {
font-size: 28px;
}
}
#current-version {
display: inline-flex;
align-items: center;
gap: 8px;
}
.version-link {
color: #5fba7d;
text-decoration: none;
font-weight: bold;
transition: color 0.2s ease;
}
.version-link:hover {
color: #7ccd9a;
text-decoration: underline;
}
.version-badge {
display: inline-block;
background: linear-gradient(135deg, #2e8b57 0%, #3cb371 100%);
color: #fff;
font-size: 10px;
font-weight: bold;
text-transform: uppercase;
padding: 2px 6px;
border-radius: 3px;
letter-spacing: 0.5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}