-
{{tab.name}}
+ @click="currentTab = tab.id">
+
+ {{tab.name}}
+
@@ -86,9 +107,15 @@
{{ $t('config.configuration') }}
{{ $t('_common.success') }} {{ $t('config.restart_note') }}
-
@@ -106,6 +133,19 @@
{{ $t('config.configuration') }}
import AudioVideo from './configs/tabs/AudioVideo.vue'
import ContainerEncoders from './configs/tabs/ContainerEncoders.vue'
import {$tp, usePlatformI18n} from './platform-i18n'
+ import {
+ Check,
+ Cpu,
+ FileCog,
+ Gamepad2,
+ Gpu,
+ Network as NetworkIcon,
+ Save,
+ Search,
+ Settings,
+ Sliders,
+ Volume2,
+ } from 'lucide-vue-next'
const app = createApp({
components: {
@@ -118,6 +158,18 @@
{{ $t('config.configuration') }}
// They will be accessible via audio-video, container-encoders only.
AudioVideo,
ContainerEncoders,
+ // icons
+ Cpu,
+ Check,
+ FileCog,
+ Gamepad2,
+ Gpu,
+ NetworkIcon,
+ Save,
+ Search,
+ Settings,
+ Sliders,
+ Volume2,
},
data() {
return {
@@ -126,6 +178,7 @@
{{ $t('config.configuration') }}
restarted: false,
config: null,
currentTab: "general",
+ searchQuery: "",
tabs: [ // TODO: Move the options to each Component instead, encapsulate.
{
id: "general",
@@ -290,9 +343,34 @@
{{ $t('config.configuration') }}
},
provide() {
return {
- platform: computed(() => this.platform)
+ platform: computed(() => this.platform),
+ searchQuery: computed(() => this.searchQuery),
}
},
+ computed: {
+ allConfigOptions() {
+ const options = [];
+ this.tabs.forEach(tab => {
+ Object.keys(tab.options).forEach(key => {
+ options.push({
+ key: key,
+ label: key.replaceAll('_', ' ').replaceAll(/\b\w/g, l => l.toUpperCase()),
+ tab: tab.name,
+ tabId: tab.id
+ });
+ });
+ });
+ return options;
+ },
+ searchResults() {
+ if (!this.searchQuery) return [];
+ const query = this.searchQuery.toLowerCase();
+ return this.allConfigOptions.filter(option =>
+ option.key.toLowerCase().includes(query) ||
+ option.label.toLowerCase().includes(query)
+ );
+ }
+ },
created() {
fetch("./api/config")
.then((r) => r.json())
@@ -344,6 +422,23 @@
{{ $t('config.configuration') }}
});
},
methods: {
+ getTabIcon(tabId) {
+ const iconMap = {
+ 'general': 'Settings',
+ 'input': 'Gamepad2',
+ 'av': 'Volume2',
+ 'network': 'NetworkIcon',
+ 'files': 'FileCog',
+ 'advanced': 'Sliders',
+ 'nv': 'Gpu',
+ 'amd': 'Gpu',
+ 'qsv': 'Gpu',
+ 'vaapi': 'Gpu',
+ 'vt': 'Gpu',
+ 'sw': 'Cpu',
+ };
+ return iconMap[tabId] || 'Settings';
+ },
forceUpdate() {
this.$forceUpdate()
},
@@ -408,6 +503,67 @@
{{ $t('config.configuration') }}
}
});
},
+ handleSearch() {
+ // Clear all highlighting
+ document.querySelectorAll('.config-search-highlight').forEach(el => {
+ el.classList.remove('config-search-highlight');
+ });
+
+ if (!this.searchQuery) {
+ // Show all form groups when search is cleared
+ document.querySelectorAll('.mb-3').forEach(el => {
+ el.style.display = '';
+ });
+ return;
+ }
+
+ const results = this.searchResults;
+
+ if (results.length === 0) {
+ return;
+ }
+
+ // Switch to the tab of the first result
+ if (results.length > 0 && results[0].tabId !== this.currentTab) {
+ this.currentTab = results[0].tabId;
+ }
+
+ // Wait for tab content to render
+ this.$nextTick(() => {
+ // Hide all form groups first
+ document.querySelectorAll('.config-page .mb-3').forEach(el => {
+ el.style.display = 'none';
+ });
+
+ // Show only matching elements
+ results.forEach(result => {
+ const element = document.getElementById(result.key);
+
+ if (element) {
+ // Show the element's container
+ const container = element.closest('.mb-3');
+ if (container) {
+ container.style.display = '';
+ }
+ }
+ });
+
+ // Scroll to and highlight the first result
+ if (results.length > 0) {
+ const firstElement = document.getElementById(results[0].key);
+ if (firstElement) {
+ const container = firstElement.closest('.mb-3');
+ if (container) {
+ container.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ container.classList.add('config-search-highlight');
+ setTimeout(() => {
+ container.classList.remove('config-search-highlight');
+ }, 3000);
+ }
+ }
+ }
+ });
+ },
},
mounted() {
// Handle hashchange events
diff --git a/src_assets/common/assets/web/featured.html b/src_assets/common/assets/web/featured.html
new file mode 100644
index 00000000000..562d61c6a8b
--- /dev/null
+++ b/src_assets/common/assets/web/featured.html
@@ -0,0 +1,436 @@
+
+
+
+
+ <%- header %>
+
+
+
+
+
+
+
{{ $t('featured.title') }}
+
{{ $t('featured.description') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('_common.loading') }}
+
+
+
+
+
+
{{ $t('_common.error') }}
+
{{ error }}
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+
{{ app.name }}
+
{{ app.tagline }}
+
+
{{ $t('featured.official') }}
+
+
+
{{ app.description }}
+
+
+
+
+
+ {{ formatNumber(app.github.stars) }}
+
+
+
+ {{ formatNumber(app.github.forks) }}
+
+
+
+ {{ formatNumber(app.github.openIssues) }}
+
+
+
+
+
+
+ {{ $t('featured.last_updated') }}: {{ formatDate(app.github.lastUpdated).relative }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ platformName(platform) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('featured.no_apps') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ selectedScreenshotIndex + 1 }} / {{ currentAppScreenshots.length }}
+
+
+
![Screenshot]()
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/index.html b/src_assets/common/assets/web/index.html
index 55f62e43557..7a02b34fc36 100644
--- a/src_assets/common/assets/web/index.html
+++ b/src_assets/common/assets/web/index.html
@@ -10,77 +10,115 @@
{{ $t('index.welcome') }}
{{ $t('index.description') }}
-
-
-
-
-
+
+
+
+
-
-
-
-
-
{{ $t('index.vigembus_not_installed_title') }}
-
{{ $t('index.vigembus_not_installed_desc') }}
-
-
-
{{ $t('index.vigembus_outdated_title') }}
-
{{ $t('index.vigembus_outdated_desc', { version: vigembus.version }) }}
+
+
+
+
+
+
+
{{ $t('index.vigembus_not_installed_title') }}
+
{{ $t('index.vigembus_not_installed_desc') }}
+
+
+
{{ $t('index.vigembus_outdated_title') }}
+
{{ $t('index.vigembus_outdated_desc', { version: vigembus.version }) }}
+
+
-
{{ $t('index.fix_now') }}
+
+
+ {{ $t('index.fix_now') }}
+
+
-
+
Version {{version.version}}
-
-
+
+
{{ $t('index.loading_latest') }}
-
+
+
+
{{ $t('index.version_dirty') }} 🌇
-
+
+
+
{{ $t('index.installed_version_not_stable') }}
+
-
+
+
{{ $t('index.version_latest') }}
+
-
-
-
-
{{ $t('index.new_pre_release') }}
+
+
-
-
-
-
{{ $t('index.new_stable') }}
+
+
@@ -95,6 +133,16 @@
{{githubVersion.release.name}}
import Navbar from './Navbar.vue'
import ResourceCard from './ResourceCard.vue'
import SunshineVersion from './sunshine_version'
+ import {
+ AlertCircle,
+ AlertTriangle,
+ FileText,
+ Wrench,
+ Package,
+ Info,
+ CheckCircle,
+ Download
+ } from 'lucide-vue-next'
// Configure marked to allow HTML
marked.setOptions({
@@ -109,7 +157,15 @@ {{githubVersion.release.name}}
let app = createApp({
components: {
Navbar,
- ResourceCard
+ ResourceCard,
+ AlertCircle,
+ AlertTriangle,
+ FileText,
+ Wrench,
+ Package,
+ Info,
+ CheckCircle,
+ Download
},
data() {
return {
@@ -200,3 +256,4 @@ {{githubVersion.release.name}}
initApp(app);
+