Add Linux App Store Web Portal with Kubernetes deployment
- React-style static web portal with Tailwind CSS - OS detection (Debian/Ubuntu, Fedora, Arch, Generic) - Dynamic install commands (apt://, appstream://, flatpak) - 9 pre-configured applications - Kubernetes: 2 replicas, LoadBalancer service, Nginx ingress - GitLab Container Registry (git.giaco.net/capitano/webapplinux) - Namespace: linuxwebapp - Added Dockerfile, nginx.conf, deploy.sh, docker-compose.yml - Updated README.md with deployment instructions
This commit is contained in:
112
frontend/apps.json
Normal file
112
frontend/apps.json
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"id": "vlc",
|
||||
"name": "VLC Media Player",
|
||||
"description": "The most complete media player ever created. Play all your favorite media formats.",
|
||||
"icon": "fa-film",
|
||||
"colors": "from-purple-500 to-indigo-600",
|
||||
"packages": {
|
||||
"apt": "vlc",
|
||||
"appstream": "org.videolan.VLC",
|
||||
"flatpak": "https://flathub.org-repo/vlc.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gimp",
|
||||
"name": "GIMP",
|
||||
"description": "GNU Image Manipulation Program - professional-grade photo editing tool.",
|
||||
"icon": "fa-image",
|
||||
"colors": "from-blue-500 to-cyan-600",
|
||||
"packages": {
|
||||
"apt": "gimp",
|
||||
"appstream": "org.gimp.GIMP",
|
||||
"flatpak": "https://flathub.org-repo/gimp.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "vscode",
|
||||
"name": "VS Code",
|
||||
"description": "Visual Studio Code - the code editor redefined for modern development.",
|
||||
"icon": "fa-code",
|
||||
"colors": "from-blue-600 to-blue-800",
|
||||
"packages": {
|
||||
"apt": "code",
|
||||
"appstream": "com.visualstudio.code",
|
||||
"flatpak": "https://flathub.org-repo/code.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "thunderbird",
|
||||
"name": "Thunderbird",
|
||||
"description": "Email client that puts control back in your hands with powerful features.",
|
||||
"icon": "fa-envelope",
|
||||
"colors": "from-orange-500 to-red-600",
|
||||
"packages": {
|
||||
"apt": "thunderbird",
|
||||
"appstream": "org.mozilla.thunderbird",
|
||||
"flatpak": "https://flathub.org-repo/thunderbird.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "libreoffice",
|
||||
"name": "LibreOffice",
|
||||
"description": "The-free-and-open-source productivity suite for documents, spreadsheets, and presentations.",
|
||||
"icon": "fa-file-alt",
|
||||
"colors": "from-teal-500 to-green-600",
|
||||
"packages": {
|
||||
"apt": "libreoffice",
|
||||
"appstream": "org.libreoffice.LibreOffice",
|
||||
"flatpak": "https://flathub.org-repo/libreoffice.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "firefox",
|
||||
"name": "Firefox",
|
||||
"description": "The web browser built for privacy, speed, and customization.",
|
||||
"icon": "fa-globe",
|
||||
"colors": "from-orange-600 to-red-700",
|
||||
"packages": {
|
||||
"apt": "firefox",
|
||||
"appstream": "org.mozilla.firefox",
|
||||
"flatpak": "https://flathub.org-repo/firefox.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "inkscape",
|
||||
"name": "Inkscape",
|
||||
"description": "Professional vector graphics editor for illustrations, diagrams, and logos.",
|
||||
"icon": "fa-pen-nib",
|
||||
"colors": "from-blue-400 to-indigo-500",
|
||||
"packages": {
|
||||
"apt": "inkscape",
|
||||
"appstream": "org.inkscape.Inkscape",
|
||||
"flatpak": "https://flathub.org-repo/inkscape.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "discord",
|
||||
"name": "Discord",
|
||||
"description": "All-in-one voice and text chat for gamers and communities.",
|
||||
"icon": "fa-comments",
|
||||
"colors": "from-indigo-500 to-purple-600",
|
||||
"packages": {
|
||||
"apt": "discord",
|
||||
"appstream": "com.discordapp.Discord",
|
||||
"flatpak": "https://flathub.org-repo/discord.flatpakref"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "github-desktop",
|
||||
"name": "GitHub Desktop",
|
||||
"description": "Simple collaboration from your desktop - git made easy.",
|
||||
"icon": "fa-github",
|
||||
"colors": "from-gray-600 to-gray-800",
|
||||
"packages": {
|
||||
"apt": "github-desktop",
|
||||
"appstream": "com.githubDesktop.githubDesktop",
|
||||
"flatpak": "https://flathub.org-repo/github-desktop.flatpakref"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
49
frontend/index.html
Normal file
49
frontend/index.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Linux App Store</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
gray: {
|
||||
850: '#1f2937',
|
||||
900: '#111827',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-gray-900 text-white">
|
||||
<nav class="bg-gray-850 border-b border-gray-700">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-store text-blue-500 text-2xl mr-3"></i>
|
||||
<span class="text-xl font-bold">Linux App Store</span>
|
||||
</div>
|
||||
<div id="os-display" class="hidden text-sm text-gray-400"></div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold mb-2">Discovery</h1>
|
||||
<p class="text-gray-400">Discover and install applications directly on your Linux system</p>
|
||||
</div>
|
||||
|
||||
<div id="apps-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
192
frontend/script.js
Normal file
192
frontend/script.js
Normal file
@@ -0,0 +1,192 @@
|
||||
const OS_TYPE = {
|
||||
DEB: 'deb',
|
||||
RPM: 'rpm',
|
||||
ARCH: 'arch',
|
||||
GENERIC: 'generic'
|
||||
};
|
||||
|
||||
function detectOS() {
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
if (userAgent.includes('ubuntu') ||
|
||||
userAgent.includes('debian') ||
|
||||
userAgent.includes('linuxmint') ||
|
||||
userAgent.includes('pop!_os')) {
|
||||
return { type: OS_TYPE.DEB, name: 'Debian/Ubuntu-based' };
|
||||
}
|
||||
|
||||
if (userAgent.includes('fedora') ||
|
||||
userAgent.includes('rhel') ||
|
||||
userAgent.includes('redhat') ||
|
||||
userAgent.includes('centos') ||
|
||||
userAgent.includes('opensuse') ||
|
||||
userAgent.includes('suse')) {
|
||||
return { type: OS_TYPE.RPM, name: 'Fedora/RedHat-based' };
|
||||
}
|
||||
|
||||
if (userAgent.includes('arch') ||
|
||||
userAgent.includes('endeavouros') ||
|
||||
userAgent.includes('manjaro')) {
|
||||
return { type: OS_TYPE.ARCH, name: 'Arch Linux' };
|
||||
}
|
||||
|
||||
return { type: OS_TYPE.GENERIC, name: 'Generic Linux' };
|
||||
}
|
||||
|
||||
function renderApps(apps) {
|
||||
const container = document.getElementById('apps-container');
|
||||
|
||||
apps.forEach(app => {
|
||||
const appCard = document.createElement('div');
|
||||
appCard.className = 'bg-gray-850 rounded-xl overflow-hidden shadow-lg hover:shadow-2xl transition-shadow duration-300 border border-gray-700';
|
||||
|
||||
appCard.innerHTML = `
|
||||
<div class="p-6">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="flex items-center">
|
||||
<div class="w-12 h-12 rounded-lg bg-gradient-to-br ${app.colors} flex items-center justify-center mr-4">
|
||||
<i class="${app.icon} fa-xl text-white"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold">${app.name}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-400 text-sm mb-6 line-clamp-2">${app.description}</p>
|
||||
|
||||
<div class="bg-gray-900 rounded-lg p-3 mb-4 text-xs text-gray-500 font-mono">
|
||||
<div class="mb-1"><i class="fas fa-terminal mr-2"></i>Installazione:</div>
|
||||
<div id="install-${app.id}">Caricamento...</div>
|
||||
</div>
|
||||
|
||||
<button onclick="installApp('${app.id}', '${app.packages.apt}', '${app.packages.appstream}', '${app.packages.flatpak}')"
|
||||
class="w-full bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white font-bold py-3 px-4 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||
<i class="fas fa-download mr-2"></i>Installa
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(appCard);
|
||||
});
|
||||
}
|
||||
|
||||
function updateInstallLink(appId, aptPackage, appstreamId, flatpakUrl) {
|
||||
const osInfo = detectOS();
|
||||
const installDiv = document.getElementById(`install-${appId}`);
|
||||
|
||||
let installCommand = '';
|
||||
let protocol = '';
|
||||
|
||||
switch (osInfo.type) {
|
||||
case OS_TYPE.DEB:
|
||||
protocol = 'apt://';
|
||||
installCommand = `${protocol}${aptPackage}`;
|
||||
break;
|
||||
case OS_TYPE.RPM:
|
||||
protocol = 'appstream://';
|
||||
installCommand = `${protocol}${appstreamId}`;
|
||||
break;
|
||||
case OS_TYPE.ARCH:
|
||||
protocol = 'appstream://';
|
||||
installCommand = `${protocol}${appstreamId} (pacman -S ${aptPackage})`;
|
||||
break;
|
||||
case OS_TYPE.GENERIC:
|
||||
protocol = 'flatpak';
|
||||
installCommand = `Download: ${flatpakUrl}`;
|
||||
break;
|
||||
}
|
||||
|
||||
installDiv.innerHTML = `<i class="fas fa-terminal mr-2"></i> ${installCommand}`;
|
||||
|
||||
const installBtn = document.querySelector(`button[onclick="installApp('${appId}', '${aptPackage}', '${appstreamId}', '${flatpakUrl}')"]`);
|
||||
|
||||
installBtn.onclick = function() {
|
||||
handleInstall(appId, aptPackage, appstreamId, flatpakUrl);
|
||||
};
|
||||
}
|
||||
|
||||
function handleInstall(appId, aptPackage, appstreamId, flatpakUrl) {
|
||||
const osInfo = detectOS();
|
||||
let url = '';
|
||||
|
||||
switch (osInfo.type) {
|
||||
case OS_TYPE.DEB:
|
||||
url = `apt://${aptPackage}`;
|
||||
break;
|
||||
case OS_TYPE.RPM:
|
||||
url = `appstream://${appstreamId}`;
|
||||
break;
|
||||
case OS_TYPE.ARCH:
|
||||
url = `appstream://${appstreamId}`;
|
||||
break;
|
||||
case OS_TYPE.GENERIC:
|
||||
url = flatpakUrl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (url.startsWith('apt://') || url.startsWith('appstream://')) {
|
||||
const protocol = url.split(':')[0];
|
||||
let command = url.replace(`${protocol}://`, '');
|
||||
|
||||
if (protocol === 'apt') {
|
||||
command = `<span class="text-green-400">sudo apt install ${command}</span>`;
|
||||
} else {
|
||||
command = `<span class="text-green-400">${protocol} install ${command}</span>`;
|
||||
}
|
||||
|
||||
const notification = createNotification(`Comando generato per ${osInfo.name}:<br>${command}`, 'success');
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => notification.remove(), 5000);
|
||||
} else if (url) {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
function createNotification(message, type) {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 bg-gray-800 border-l-4 border-${type === 'success' ? 'green' : 'red'}-500 text-white px-6 py-4 rounded shadow-lg z-50 transition-all duration-500 transform translate-x-full`;
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-circle'} text-${type === 'success' ? 'green' : 'red'}-500 mr-3"></i>
|
||||
<div>${message}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
setTimeout(() => {
|
||||
notification.classList.remove('translate-x-full');
|
||||
}, 100);
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
function highlightOS(osInfo) {
|
||||
const osDisplay = document.getElementById('os-display');
|
||||
if (osDisplay) {
|
||||
osDisplay.innerHTML = `<i class="fab fa-${osInfo.name.includes('Ubuntu') ? 'ubuntu' : osInfo.name.includes('Fedora') ? 'fedora' : osInfo.name.includes('Arch') ? 'linux' : 'linux'} mr-2"></i>${osInfo.name}`;
|
||||
osDisplay.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
fetch('apps.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const osInfo = detectOS();
|
||||
highlightOS(osInfo);
|
||||
renderApps(data.apps);
|
||||
|
||||
data.apps.forEach(app => {
|
||||
updateInstallLink(app.id, app.packages.apt, app.packages.appstream, app.packages.flatpak);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading apps:', error);
|
||||
const container = document.getElementById('apps-container');
|
||||
container.innerHTML = `<div class="col-span-full text-center py-10 text-red-500">
|
||||
<i class="fas fa-exclamation-triangle text-3xl mb-2"></i>
|
||||
<p>Errore nel caricamento delle applicazioni</p>
|
||||
</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
Reference in New Issue
Block a user