mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'jellyfin:master' into add/device-logos
This commit is contained in:
commit
7ab1edd3c5
16 changed files with 70 additions and 20 deletions
|
@ -305,10 +305,16 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
[dir="rtl"] & {
|
[dir="rtl"] & {
|
||||||
transition: right ease-in-out 0.3s, padding ease-in-out 0.3s;
|
transition: right ease-in-out 0.3s, padding ease-in-out 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .page {
|
||||||
|
// Fix pointer events being swallowed by the react root when a dashboard page is not rendered by react
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.centerMessage {
|
.centerMessage {
|
||||||
|
|
|
@ -77,6 +77,7 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder';
|
||||||
import('../../components/prompt/prompt').then(({default: prompt}) => {
|
import('../../components/prompt/prompt').then(({default: prompt}) => {
|
||||||
prompt({
|
prompt({
|
||||||
label: globalize.translate('LabelNewName'),
|
label: globalize.translate('LabelNewName'),
|
||||||
|
description: globalize.translate('MessageRenameMediaFolder'),
|
||||||
confirmText: globalize.translate('ButtonRename')
|
confirmText: globalize.translate('ButtonRename')
|
||||||
}).then(function (newName) {
|
}).then(function (newName) {
|
||||||
if (newName && newName != virtualFolder.Name) {
|
if (newName && newName != virtualFolder.Name) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<div id="pluginCatalogPage" data-role="page" class="page type-interior pluginConfigurationPage withTabs fullWidthContent">
|
<div id="pluginCatalogPage" data-role="page" class="page type-interior pluginConfigurationPage withTabs fullWidthContent">
|
||||||
<div>
|
<div>
|
||||||
<div class="content-primary">
|
<div class="content-primary">
|
||||||
|
<div class="inputContainer">
|
||||||
|
<input id="txtSearchPlugins" name="txtSearchPlugins" type="text" is="emby-input" label="${Search}" />
|
||||||
|
</div>
|
||||||
<div id="noPlugins" class="hide">${MessageNoAvailablePlugins}</div>
|
<div id="noPlugins" class="hide">${MessageNoAvailablePlugins}</div>
|
||||||
<div id="pluginTiles" style="text-align:left;"></div>
|
<div id="pluginTiles" style="text-align:left;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -86,10 +86,37 @@ function populateList(options) {
|
||||||
options.noItemsElement.classList.remove('hide');
|
options.noItemsElement.classList.remove('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const searchBar = document.getElementById('txtSearchPlugins');
|
||||||
|
if (searchBar) {
|
||||||
|
searchBar.addEventListener('input', () => onSearchBarType(searchBar));
|
||||||
|
}
|
||||||
|
|
||||||
options.catalogElement.innerHTML = html;
|
options.catalogElement.innerHTML = html;
|
||||||
loading.hide();
|
loading.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSearchBarType(searchBar) {
|
||||||
|
const filter = searchBar.value.toLowerCase();
|
||||||
|
for (const header of document.querySelectorAll('div .verticalSection')) {
|
||||||
|
// keep track of shown cards after each search
|
||||||
|
let shown = 0;
|
||||||
|
for (const card of header.querySelectorAll('div .card')) {
|
||||||
|
if (filter && filter != '' && !card.textContent.toLowerCase().includes(filter)) {
|
||||||
|
card.style.display = 'none';
|
||||||
|
} else {
|
||||||
|
card.style.display = 'unset';
|
||||||
|
shown++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// hide title if no cards are shown
|
||||||
|
if (shown <= 0) {
|
||||||
|
header.style.display = 'none';
|
||||||
|
} else {
|
||||||
|
header.style.display = 'unset';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getPluginHtml(plugin, options, installedPlugins) {
|
function getPluginHtml(plugin, options, installedPlugins) {
|
||||||
let html = '';
|
let html = '';
|
||||||
let href = plugin.externalUrl ? plugin.externalUrl : '#/addplugin.html?name=' + encodeURIComponent(plugin.name) + '&guid=' + plugin.guid;
|
let href = plugin.externalUrl ? plugin.externalUrl : '#/addplugin.html?name=' + encodeURIComponent(plugin.name) + '&guid=' + plugin.guid;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<div id="pluginsPage" data-role="page" class="page type-interior pluginConfigurationPage withTabs fullWidthContent">
|
<div id="pluginsPage" data-role="page" class="page type-interior pluginConfigurationPage withTabs fullWidthContent">
|
||||||
<div>
|
<div>
|
||||||
<div class="content-primary">
|
<div class="content-primary">
|
||||||
|
<div class="inputContainer">
|
||||||
|
<input id="txtSearchPlugins" name="txtSearchPlugins" type="text" is="emby-input" label="${Search}" />
|
||||||
|
</div>
|
||||||
<div class="installedPlugins"></div>
|
<div class="installedPlugins"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -112,7 +112,6 @@ function populateList(page, plugins, pluginConfigurationPages) {
|
||||||
if (plugin1.Name > plugin2.Name) {
|
if (plugin1.Name > plugin2.Name) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -136,6 +135,12 @@ function populateList(page, plugins, pluginConfigurationPages) {
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add search box listener
|
||||||
|
const searchBar = page.querySelector('#txtSearchPlugins');
|
||||||
|
if (searchBar) {
|
||||||
|
searchBar.addEventListener('input', () => onFilterType(page, searchBar));
|
||||||
|
}
|
||||||
|
|
||||||
installedPluginsElement.innerHTML = html;
|
installedPluginsElement.innerHTML = html;
|
||||||
loading.hide();
|
loading.hide();
|
||||||
}
|
}
|
||||||
|
@ -239,6 +244,17 @@ function onInstalledPluginsClick(e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onFilterType(page, searchBar) {
|
||||||
|
const filter = searchBar.value.toLowerCase();
|
||||||
|
for (const card of page.querySelectorAll('.card')) {
|
||||||
|
if (filter && filter != '' && !card.textContent.toLowerCase().includes(filter)) {
|
||||||
|
card.style.display = 'none';
|
||||||
|
} else {
|
||||||
|
card.style.display = 'unset';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pageIdOn('pageshow', 'pluginsPage', function () {
|
pageIdOn('pageshow', 'pluginsPage', function () {
|
||||||
libraryMenu.setTabs('plugins', 0, getTabs);
|
libraryMenu.setTabs('plugins', 0, getTabs);
|
||||||
reloadList(this);
|
reloadList(this);
|
||||||
|
|
|
@ -28,24 +28,15 @@ import cardBuilder from '../../../components/cardbuilder/cardBuilder';
|
||||||
const items = servers.map(function (server) {
|
const items = servers.map(function (server) {
|
||||||
return {
|
return {
|
||||||
name: server.Name,
|
name: server.Name,
|
||||||
showIcon: true,
|
icon: 'storage',
|
||||||
icon: 'cast',
|
|
||||||
cardType: '',
|
cardType: '',
|
||||||
id: server.Id,
|
id: server.Id,
|
||||||
server: server
|
server: server
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
let html = items.map(function (item) {
|
let html = items.map(function (item) {
|
||||||
let cardImageContainer;
|
|
||||||
|
|
||||||
if (item.showIcon) {
|
|
||||||
cardImageContainer = '<span class="cardImageIcon material-icons ' + item.icon + '" aria-hidden="true"></span>';
|
|
||||||
} else {
|
|
||||||
cardImageContainer = '<div class="cardImage" style="' + item.cardImageStyle + '"></div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO move card creation code to Card component
|
// TODO move card creation code to Card component
|
||||||
|
const cardImageContainer = '<span class="cardImageIcon material-icons ' + item.icon + '" aria-hidden="true"></span>';
|
||||||
let cssClass = 'card overflowSquareCard loginSquareCard scalableCard overflowSquareCard-scalable';
|
let cssClass = 'card overflowSquareCard loginSquareCard scalableCard overflowSquareCard-scalable';
|
||||||
|
|
||||||
if (layoutManager.tv) {
|
if (layoutManager.tv) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkQuickConnectPreferences listItem-border hide">
|
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkQuickConnectPreferences listItem-border hide">
|
||||||
<div class="listItem">
|
<div class="listItem">
|
||||||
<span class="material-icons listItemIcon listItemIcon-transparent tap_and_play" aria-hidden="true"></span>
|
<span class="material-icons listItemIcon listItemIcon-transparent phonelink_lock" aria-hidden="true"></span>
|
||||||
<div class="listItemBody">
|
<div class="listItemBody">
|
||||||
<div class="listItemBodyText">${QuickConnect}</div>
|
<div class="listItemBodyText">${QuickConnect}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
<h2 class="sectionTitle" style="padding-left:.25em;">${HeaderUser}</h2>
|
<h2 class="sectionTitle" style="padding-left:.25em;">${HeaderUser}</h2>
|
||||||
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="selectServer hide listItem-border">
|
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="selectServer hide listItem-border">
|
||||||
<div class="listItem">
|
<div class="listItem">
|
||||||
<span class="material-icons listItemIcon listItemIcon-transparent wifi" aria-hidden="true"></span>
|
<span class="material-icons listItemIcon listItemIcon-transparent storage" aria-hidden="true"></span>
|
||||||
<div class="listItemBody">
|
<div class="listItemBody">
|
||||||
<div class="listItemBodyText">${SelectServer}</div>
|
<div class="listItemBodyText">${SelectServer}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import appSettings from '../../scripts/settings/appSettings';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
import * as userSettings from '../../scripts/settings/userSettings';
|
||||||
import { playbackManager } from '../../components/playback/playbackmanager';
|
import { playbackManager } from '../../components/playback/playbackmanager';
|
||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import castSenderApiLoader from '../../components/castSenderApi';
|
import castSenderApiLoader from './castSenderApi';
|
||||||
import ServerConnections from '../../components/ServerConnections';
|
import ServerConnections from '../../components/ServerConnections';
|
||||||
import alert from '../../components/alert';
|
import alert from '../../components/alert';
|
||||||
import Events from '../../utils/events.ts';
|
import Events from '../../utils/events.ts';
|
||||||
|
|
|
@ -325,7 +325,7 @@ import '../assets/css/flexstyles.scss';
|
||||||
html += '</h3>';
|
html += '</h3>';
|
||||||
|
|
||||||
if (appHost.supports('multiserver')) {
|
if (appHost.supports('multiserver')) {
|
||||||
html += `<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder btnSelectServer" data-itemid="selectserver" href="#"><span class="material-icons navMenuOptionIcon wifi" aria-hidden="true"></span><span class="navMenuOptionText">${globalize.translate('SelectServer')}</span></a>`;
|
html += `<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder btnSelectServer" data-itemid="selectserver" href="#"><span class="material-icons navMenuOptionIcon storage" aria-hidden="true"></span><span class="navMenuOptionText">${globalize.translate('SelectServer')}</span></a>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
html += `<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder btnSettings" data-itemid="settings" href="#"><span class="material-icons navMenuOptionIcon settings" aria-hidden="true"></span><span class="navMenuOptionText">${globalize.translate('Settings')}</span></a>`;
|
html += `<a is="emby-linkbutton" class="navMenuOption lnkMediaFolder btnSettings" data-itemid="settings" href="#"><span class="material-icons navMenuOptionIcon settings" aria-hidden="true"></span><span class="navMenuOptionText">${globalize.translate('Settings')}</span></a>`;
|
||||||
|
|
|
@ -1679,5 +1679,6 @@
|
||||||
"IgnoreDtsHelp": "Vypnutím se mohou vyřešit některé problémy, např. chybějící zvuk u kanálů s oddělenými zvukovými a video stopami.",
|
"IgnoreDtsHelp": "Vypnutím se mohou vyřešit některé problémy, např. chybějící zvuk u kanálů s oddělenými zvukovými a video stopami.",
|
||||||
"IgnoreDts": "Ignorovat DTS (časové razítko dekódování)",
|
"IgnoreDts": "Ignorovat DTS (časové razítko dekódování)",
|
||||||
"OptionDateEpisodeAdded": "Datum přidání epizody",
|
"OptionDateEpisodeAdded": "Datum přidání epizody",
|
||||||
"OptionDateShowAdded": "Datum přidání pořadu"
|
"OptionDateShowAdded": "Datum přidání pořadu",
|
||||||
|
"MessageRenameMediaFolder": "Přejmenování knihovny médií způsobí ztrátu všech metadat, postupujte proto s opatrností."
|
||||||
}
|
}
|
||||||
|
|
|
@ -1085,6 +1085,7 @@
|
||||||
"MessagePluginInstalled": "The plugin has been successfully installed. The server will need to be restarted for changes to take effect.",
|
"MessagePluginInstalled": "The plugin has been successfully installed. The server will need to be restarted for changes to take effect.",
|
||||||
"MessagePluginInstallError": "An error occurred while installing the plugin.",
|
"MessagePluginInstallError": "An error occurred while installing the plugin.",
|
||||||
"MessageReenableUser": "See below to reenable",
|
"MessageReenableUser": "See below to reenable",
|
||||||
|
"MessageRenameMediaFolder": "Renaming a media library will cause all metadata to be lost, proceed with caution.",
|
||||||
"MessageSent": "Message sent.",
|
"MessageSent": "Message sent.",
|
||||||
"MessageSyncPlayCreateGroupDenied": "Permission required to create a group.",
|
"MessageSyncPlayCreateGroupDenied": "Permission required to create a group.",
|
||||||
"MessageSyncPlayDisabled": "SyncPlay disabled.",
|
"MessageSyncPlayDisabled": "SyncPlay disabled.",
|
||||||
|
|
|
@ -1679,5 +1679,6 @@
|
||||||
"IgnoreDtsHelp": "La désactivation de cette option peut résoudre certains problèmes, par ex. audio manquant sur les canaux avec des flux audio et vidéo séparés.",
|
"IgnoreDtsHelp": "La désactivation de cette option peut résoudre certains problèmes, par ex. audio manquant sur les canaux avec des flux audio et vidéo séparés.",
|
||||||
"OptionDateShowAdded": "Date d'ajout de la série",
|
"OptionDateShowAdded": "Date d'ajout de la série",
|
||||||
"OptionDateEpisodeAdded": "Date d'ajout de l'épisode",
|
"OptionDateEpisodeAdded": "Date d'ajout de l'épisode",
|
||||||
"IgnoreDts": "Ignorer DTS (horodatage de décodage)"
|
"IgnoreDts": "Ignorer DTS (horodatage de décodage)",
|
||||||
|
"MessageRenameMediaFolder": "Renommer une médiathèque entraînera la perte de toutes les métadonnées, procédez avec prudence."
|
||||||
}
|
}
|
||||||
|
|
|
@ -582,7 +582,7 @@
|
||||||
"Image": "Зображення",
|
"Image": "Зображення",
|
||||||
"Identify": "Ідентифікувати",
|
"Identify": "Ідентифікувати",
|
||||||
"Horizontal": "Горизонтально",
|
"Horizontal": "Горизонтально",
|
||||||
"Home": "Домівка",
|
"Home": "Головна",
|
||||||
"HideWatchedContentFromLatestMedia": "Приховати переглянуте з останніх медіа",
|
"HideWatchedContentFromLatestMedia": "Приховати переглянуте з останніх медіа",
|
||||||
"Hide": "Приховати",
|
"Hide": "Приховати",
|
||||||
"Help": "Допомога",
|
"Help": "Допомога",
|
||||||
|
|
|
@ -109,7 +109,7 @@ const config = {
|
||||||
if (packageName.startsWith('@')) {
|
if (packageName.startsWith('@')) {
|
||||||
const parts = module.context
|
const parts = module.context
|
||||||
.substring(module.context.lastIndexOf(packageName))
|
.substring(module.context.lastIndexOf(packageName))
|
||||||
.split('/');
|
.split(/[\\/]/);
|
||||||
return `node_modules.${parts[0]}.${parts[1]}`;
|
return `node_modules.${parts[0]}.${parts[1]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue