mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-08-07 02:00:45 +00:00
refactor: clients section to dynamically fetch from app-directory (#5380)
This commit is contained in:
committed by
GitHub
parent
c6bef3397d
commit
c58fd6d8c6
@@ -1,180 +0,0 @@
|
||||
---
|
||||
- name: "Android"
|
||||
type: "official"
|
||||
github: "https://github.com/moonlight-stream/moonlight-android"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/android.svg"
|
||||
alt: "Android"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Get it on Google Play"
|
||||
url: "https://play.google.com/store/apps/details?id=com.limelight"
|
||||
img_src: "https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"
|
||||
img_height: 60
|
||||
- label: "Available at Amazon Appstore"
|
||||
url: "https://www.amazon.com/gp/product/B00JK4MFN2"
|
||||
img_src: "https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/devportal2/res/images/amazon-appstore-badge-english-black.png" # yamllint disable rule:line-length
|
||||
img_height: 60
|
||||
img_style: "padding: 10px;"
|
||||
- label: "Get it on F-Droid"
|
||||
url: "https://f-droid.org/packages/com.limelight"
|
||||
img_src: "https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
img_height: 60
|
||||
|
||||
- name: "iOS"
|
||||
type: "official"
|
||||
github: "https://github.com/moonlight-stream/moonlight-ios"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/ios.svg"
|
||||
alt: "iOS"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/appletv.svg"
|
||||
alt: "Apple TV"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download on the App Store"
|
||||
url: "https://apps.apple.com/us/app/moonlight-game-streaming/id1000551566"
|
||||
img_src: "https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg"
|
||||
img_height: 40
|
||||
- label: "Download on Apple TV"
|
||||
url: "https://apps.apple.com/us/app/moonlight-game-streaming/id1000551566"
|
||||
img_src: "https://developer.apple.com/app-store/marketing/guidelines/images/badge-download-on-apple-tv.svg"
|
||||
img_height: 40
|
||||
|
||||
- name: "QT"
|
||||
type: "official"
|
||||
github: "https://github.com/moonlight-stream/moonlight-qt"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/linux.svg"
|
||||
alt: "Linux"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/macos.svg"
|
||||
alt: "macOS"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/icons/windows.svg"
|
||||
alt: "Windows"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/steam.svg"
|
||||
alt: "Steam"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download on GitHub"
|
||||
url: "https://github.com/moonlight-stream/moonlight-qt/releases"
|
||||
icon_fa: "fab fa-github"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "Embedded"
|
||||
type: "official"
|
||||
github: "https://github.com/moonlight-stream/moonlight-embedded"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/raspberrypi.svg"
|
||||
alt: "Raspberry Pi"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download"
|
||||
url: "https://github.com/irtimmer/moonlight-embedded/wiki/Packages"
|
||||
icon_fa: "fas fa-download"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "Xbox One/Series"
|
||||
type: "community"
|
||||
github: "https://github.com/TheElixZammuto/moonlight-xbox"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/icons/xbox.svg"
|
||||
alt: "Xbox"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Get it from Microsoft"
|
||||
url: "https://apps.microsoft.com/store/detail/moonlight-uwp/9MW1BS08ZBTH"
|
||||
img_src: "https://get.microsoft.com/images/en-us%20dark.svg"
|
||||
img_height: 40
|
||||
|
||||
- name: "PS Vita"
|
||||
type: "community"
|
||||
github: "https://github.com/xyzz/vita-moonlight"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/playstationvita.svg"
|
||||
alt: "PlayStation Vita"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download on GitHub"
|
||||
url: "https://github.com/xyzz/vita-moonlight/releases"
|
||||
icon_fa: "fab fa-github"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "Moonlight Switch"
|
||||
type: "community"
|
||||
github: "https://github.com/XITRIX/Moonlight-Switch"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/icons/nintendo-switch.svg"
|
||||
alt: "Nintendo Switch"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/android.svg"
|
||||
alt: "Android"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/appletv.svg"
|
||||
alt: "Apple TV"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/ios.svg"
|
||||
alt: "iOS"
|
||||
invert: true
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/macos.svg"
|
||||
alt: "macOS"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download on GitHub"
|
||||
url: "https://github.com/XITRIX/Moonlight-Switch/releases"
|
||||
icon_fa: "fab fa-github"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "Nintendo Wii U"
|
||||
type: "community"
|
||||
github: "https://github.com/GaryOderNichts/moonlight-wiiu"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@13/icons/wiiu.svg"
|
||||
alt: "Wii U"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download"
|
||||
url: "https://github.com/GaryOderNichts/moonlight-wiiu#quick-start"
|
||||
icon_fa: "fas fa-download"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "New Nintendo 3DS"
|
||||
type: "community"
|
||||
github: "https://github.com/zoeyjodon/moonlight-N3DS"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@13/icons/nintendo3ds.svg"
|
||||
alt: "3DS"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download"
|
||||
url: "https://github.com/zoeyjodon/moonlight-N3DS"
|
||||
icon_fa: "fas fa-download"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "LG webOS TV"
|
||||
type: "community"
|
||||
github: "https://github.com/mariotaku/moonlight-tv"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/lg.svg"
|
||||
alt: "LG webOS TV"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download"
|
||||
url: "https://github.com/mariotaku/moonlight-tv#download"
|
||||
icon_fa: "fas fa-download"
|
||||
btn_class: "btn btn-info"
|
||||
|
||||
- name: "Samsung Tizen TV"
|
||||
type: "community"
|
||||
github: "https://github.com/brightcraft/moonlight-tizen"
|
||||
icons:
|
||||
- src: "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/samsung.svg"
|
||||
alt: "Samsung Tizen TV"
|
||||
invert: true
|
||||
downloads:
|
||||
- label: "Download on GitHub"
|
||||
url: "https://github.com/brightcraft/moonlight-tizen/releases"
|
||||
icon_fa: "fab fa-github"
|
||||
btn_class: "btn btn-info"
|
||||
+109
-51
@@ -59,57 +59,8 @@ cover-img:
|
||||
<section class="py-5" id="Clients">
|
||||
<div class="container px-auto">
|
||||
<h2 class="text-center fw-bolder my-5">Clients</h2>
|
||||
<div class="row gx-5">
|
||||
{% for client in site.data.clients %}
|
||||
<div class="col-md-6 col-lg-4 mb-5">
|
||||
<div class="card-custom h-100 shadow border-0 rounded-0 d-flex flex-column">
|
||||
<div class="card-body p-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="icon">
|
||||
{% for icon in client.icons %}
|
||||
<img {% if icon.invert %}class="invert"{% endif %} src="{{ icon.src }}" alt="{{ icon.alt }}"/>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
<h5 class="fw-bolder mb-0">
|
||||
<a href="{{ client.github }}" target="_blank" class="text-decoration-none project-card-link crowdin-ignore">
|
||||
{{ client.name }}
|
||||
</a>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
{% if client.type == "official" %}
|
||||
<span class="badge text-bg-info rounded-pill">Official</span>
|
||||
{% elsif client.type == "community" %}
|
||||
<span class="badge text-bg-warning rounded-pill">Community</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if client.downloads %}
|
||||
<div class="card-footer p-3 px-4">
|
||||
{% for download in client.downloads %}
|
||||
<div class="{% unless forloop.last %}pb-3{% endunless %}">
|
||||
{% if download.img_src %}
|
||||
<a href="{{ download.url }}" target="_blank"{% if download.btn_class %} class="{{ download.btn_class }}"{% endif %}>
|
||||
<img alt="{{ download.label }}"
|
||||
src="{{ download.img_src }}"
|
||||
height="{{ download.img_height }}"
|
||||
{% if download.img_style %}style="{{ download.img_style }}"{% endif %}/>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ download.url }}" target="_blank" class="{{ download.btn_class | default: 'btn btn-info' }}">
|
||||
{% if download.icon_fa %}<i class="{{ download.icon_fa }}"></i>{% endif %}
|
||||
{{ download.label }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="row gx-5" id="clients-container">
|
||||
<!-- Dynamically populated from sunshine.json -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -245,4 +196,111 @@ cover-img:
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch clients from app directory
|
||||
fetch('https://app.lizardbyte.dev/app-directory/sunshine.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const clientsContainer = document.getElementById('clients-container');
|
||||
if (!clientsContainer) return;
|
||||
|
||||
const apps = data.apps || [];
|
||||
|
||||
apps.forEach(app => {
|
||||
let iconsHtml = '';
|
||||
|
||||
// Dynamic generation from JSON icons array
|
||||
if (app.icons && Array.isArray(app.icons)) {
|
||||
app.icons.forEach(icon => {
|
||||
iconsHtml += `<img ${icon.invert ? 'class="invert"' : ''} src="${icon.src}" alt="${icon.alt}"/>`;
|
||||
});
|
||||
}
|
||||
|
||||
const typeBadge = app.official
|
||||
? '<span class="badge text-bg-info rounded-pill">Official</span>'
|
||||
: '<span class="badge text-bg-warning rounded-pill">Community</span>';
|
||||
|
||||
let downloadsHtml = '';
|
||||
|
||||
// Dynamic generation from JSON downloads array
|
||||
if (app.downloads && Array.isArray(app.downloads)) {
|
||||
app.downloads.forEach((download, index) => {
|
||||
const isLast = index === app.downloads.length - 1;
|
||||
const pbClass = isLast ? '' : ' pb-3';
|
||||
|
||||
if (download.img) {
|
||||
let styleAttr = '';
|
||||
let heightAttr = '40';
|
||||
let imgHost = '';
|
||||
try { imgHost = new URL(download.img).hostname; } catch (e) {}
|
||||
|
||||
if (imgHost === 'play.google.com' || imgHost.endsWith('.ssl-images-amazon.com') || imgHost === 'fdroid.gitlab.io') {
|
||||
heightAttr = '60';
|
||||
}
|
||||
if (imgHost.endsWith('.ssl-images-amazon.com')) {
|
||||
styleAttr = 'style="padding: 10px;"';
|
||||
}
|
||||
|
||||
downloadsHtml += `
|
||||
<div class="${pbClass.trim()}">
|
||||
<a href="${download.url}" target="_blank">
|
||||
<img alt="${download.label}"
|
||||
src="${download.img}"
|
||||
height="${heightAttr}"
|
||||
${styleAttr}/>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
let btnClass = 'btn btn-info';
|
||||
let iconHtml = '<i class="fas fa-download"></i> ';
|
||||
let urlHost = '';
|
||||
try { urlHost = new URL(download.url).hostname; } catch (e) {}
|
||||
|
||||
if (urlHost === 'github.com') {
|
||||
iconHtml = '<i class="fab fa-github"></i> ';
|
||||
}
|
||||
downloadsHtml += `
|
||||
<div class="${pbClass.trim()}">
|
||||
<a href="${download.url}" target="_blank" class="${btnClass}">
|
||||
${iconHtml}${download.label}
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const projectLink = (app.links && app.links.github) || (app.links && app.links.website) || '#';
|
||||
|
||||
const clientHtml = `
|
||||
<div class="col-md-6 col-lg-4 mb-5">
|
||||
<div class="card-custom h-100 shadow border-0 rounded-0 d-flex flex-column">
|
||||
<div class="card-body p-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="icon">
|
||||
${iconsHtml}
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
<h5 class="fw-bolder mb-0">
|
||||
<a href="${projectLink}" target="_blank" class="text-decoration-none project-card-link crowdin-ignore">
|
||||
${app.name}
|
||||
</a>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
${typeBadge}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${downloadsHtml ? `
|
||||
<div class="card-footer p-3 px-4">
|
||||
${downloadsHtml}
|
||||
</div>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
clientsContainer.innerHTML += clientHtml;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -133,22 +133,46 @@
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<div class="d-flex gap-2 flex-wrap align-items-center">
|
||||
<template v-if="app.downloads && app.downloads.length > 0">
|
||||
<a
|
||||
v-for="(download, index) in app.downloads"
|
||||
:key="index"
|
||||
:href="download.url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:class="download.img ? 'flex-fill text-center d-inline-flex align-items-center justify-content-center' : 'btn btn-primary btn-sm flex-fill d-inline-flex align-items-center justify-content-center gap-1'">
|
||||
|
||||
<img v-if="download.img"
|
||||
:src="download.img"
|
||||
:alt="download.label"
|
||||
:height="getDownloadHeight(download.img)"
|
||||
:style="getDownloadStyle(download.img)" />
|
||||
|
||||
<template v-else>
|
||||
<simple-icon v-if="isGithubUrl(download.url)" icon="GitHub" :size="16" class="icon"></simple-icon>
|
||||
<arrow-down-circle v-else :size="16" class="icon"></arrow-down-circle>
|
||||
{{ download.label }}
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a
|
||||
v-if="app.links && app.links.download"
|
||||
:href="app.links.download"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-primary btn-sm flex-fill">
|
||||
class="btn btn-primary btn-sm flex-fill d-inline-flex align-items-center justify-content-center gap-1">
|
||||
<arrow-down-circle :size="16" class="icon"></arrow-down-circle>
|
||||
{{ $t('featured.get') }}
|
||||
</a>
|
||||
</template>
|
||||
<a
|
||||
v-if="app.links && app.links.documentation"
|
||||
:href="app.links.documentation"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
class="btn btn-outline-primary btn-sm d-inline-flex align-items-center justify-content-center gap-1"
|
||||
:title="$t('featured.documentation')">
|
||||
<external-link :size="16" class="icon"></external-link>
|
||||
{{ $t('featured.docs') }}
|
||||
@@ -158,7 +182,7 @@
|
||||
:href="app.links.website"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-outline-secondary btn-sm"
|
||||
class="btn btn-outline-secondary btn-sm d-inline-flex align-items-center justify-content-center"
|
||||
:title="$t('featured.website')">
|
||||
<external-link :size="16" class="icon"></external-link>
|
||||
</a>
|
||||
@@ -167,7 +191,7 @@
|
||||
:href="app.links.github"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="btn btn-outline-secondary btn-sm"
|
||||
class="btn btn-outline-secondary btn-sm d-inline-flex align-items-center justify-content-center"
|
||||
:title="$t('featured.github')">
|
||||
<simple-icon icon="GitHub" :size="16" class="icon"></simple-icon>
|
||||
</a>
|
||||
@@ -438,6 +462,32 @@
|
||||
const relative = formatDistanceToNow(date, { addSuffix: true });
|
||||
|
||||
return { relative, absolute };
|
||||
},
|
||||
getDownloadHeight(img) {
|
||||
if (!img) return '40';
|
||||
let imgHost = '';
|
||||
try { imgHost = new URL(img).hostname; } catch (e) {}
|
||||
if (imgHost === 'play.google.com' || imgHost.endsWith('.ssl-images-amazon.com') || imgHost === 'fdroid.gitlab.io') {
|
||||
return '60';
|
||||
}
|
||||
return '40';
|
||||
},
|
||||
getDownloadStyle(img) {
|
||||
if (!img) return '';
|
||||
let imgHost = '';
|
||||
try { imgHost = new URL(img).hostname; } catch (e) {}
|
||||
if (imgHost.endsWith('.ssl-images-amazon.com')) {
|
||||
return 'padding: 10px;';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
isGithubUrl(url) {
|
||||
if (!url) return false;
|
||||
try {
|
||||
return new URL(url).hostname === 'github.com';
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user