110 Commits

Author SHA1 Message Date
Daniel
08c06054c1 Add novachromic 2021-02-11 00:39:42 +01:00
Daniel
df8f15ad1c Merge branch 'master' into cssEditor 2020-12-11 17:53:03 +01:00
Daniel
23b12cc3ea Merge pull request #11 from prayag17/cssEditor
Theming Previews
2020-12-11 17:49:55 +01:00
Prayag
4ff7da8772 Beautify JSON 2020-12-11 21:27:42 +05:30
Prayag
b987503f86 Change font size of legend 2020-12-11 21:25:09 +05:30
Prayag
2162b79309 Themed Preview 2020-12-11 21:23:07 +05:30
Prayag
dce0da67ff Add more images 2020-12-11 21:19:23 +05:30
Mister Rajoy
9924e23b0d Add preview section title 2020-12-11 16:46:05 +01:00
Prayag
1269a4dec3 Add non present images 2020-12-11 21:14:38 +05:30
Prayag
3e465cf4c8 Merge pull request #8 from danieladov/cssEditor
Css editor
2020-12-11 21:13:59 +05:30
Prayag
b9511d2501 Fix code 2020-12-11 21:13:47 +05:30
Mister Rajoy
1cb7b215ab Bugs Fixed 2020-12-11 16:30:38 +01:00
Prayag
435c256ec3 Theme previews 2020-12-11 20:50:27 +05:30
Daniel
0d1b0ceb76 Merge pull request #10 from prayag17/cssEditor
Preview Images
2020-12-11 16:15:38 +01:00
Prayag
93b25fc4f1 Add names to previews and fix the size of images 2020-12-11 20:40:45 +05:30
Prayag
6f18c554f7 Merge pull request #7 from danieladov/cssEditor
Css editor
2020-12-11 19:04:51 +05:30
Prayag
5e8c3e00d6 Add image links 2020-12-11 19:04:17 +05:30
Mister Rajoy
468334bb0b Add preview support 2020-12-11 12:36:10 +01:00
Mister Rajoy
63d3de9bfa Fix Json 2020-12-11 12:12:14 +01:00
Mister Rajoy
2acab28803 Add previews to JSON 2020-12-11 12:05:13 +01:00
Prayag
1b19253875 Merge pull request #6 from danieladov/cssEditor
Fix color fallback
2020-12-10 13:41:57 +05:30
Mister Rajoy
4b40c1a784 Fix color fallback 2020-12-09 19:27:37 +01:00
Daniel
6b8e6738b4 Merge pull request #9 from nichobi/patch-1
Correct help link to point to the right plugin
2020-12-09 14:11:22 +01:00
Nicholas Boyd Isacsson
c9c890a7f0 Correct help link to point to the right plugin 2020-12-09 13:43:13 +01:00
Prayag
7900d7a0dc Merge pull request #5 from danieladov/patch-4
Fix syntax errors
2020-12-08 21:15:01 +05:30
Daniel
d951da15d9 Update skins-3.0.json 2020-12-08 13:51:46 +01:00
Prayag
34e0388afe Update skins-3.0.json 2020-12-08 08:57:24 +05:30
Prayag
76f5e3675b Update skins-3.0.json 2020-12-08 08:40:34 +05:30
Prayag
4160e753ff Merge pull request #4 from danieladov/patch-2
Fix JSON
2020-12-07 08:04:54 +05:30
Daniel
dd7100a730 Fix JSON 2020-12-06 17:44:04 +01:00
Prayag
86121c93e3 Update skins-3.0.json 2020-12-06 21:28:03 +05:30
Prayag
cfeaaaff50 Fixed my preview JSON Code 2020-12-06 21:26:52 +05:30
Prayag
b29b4d66b2 Added links to Preview images 2020-12-05 21:46:28 +05:30
Prayag
6896f08184 Merge pull request #3 from danieladov/cssEditor
Css editor
2020-12-05 21:16:40 +05:30
Mister Rajoy
4b7fdd2457 Fix json 2020-12-04 17:06:01 +01:00
Daniel
0c21a8c617 Merge pull request #8 from prayag17/cssEditor
Few bug fix
2020-12-04 16:10:07 +01:00
Prayag
d82164c01b Add css to border-radius 2020-12-04 19:46:18 +05:30
Prayag
6e95664ca3 Remove @import for border radius and bg blur 2020-12-04 19:41:09 +05:30
Prayag
40ba7ed152 Fixed unexpected token '}' 2020-12-04 14:38:46 +05:30
Prayag
8481cb96ed Merge pull request #2 from danieladov/cssEditor
Css editor
2020-12-03 09:09:25 +05:30
Mister Rajoy
c35e9621c9 Fix selected option recognition 2020-12-02 14:17:34 +01:00
Prayag
878b0a2705 Fixed Compile Error 2020-12-02 16:29:04 +05:30
Mister Rajoy
3002c1defb Fix compile errors 2020-12-01 16:08:16 +01:00
Prayag
425b898beb Update README.md 2020-12-01 20:33:03 +05:30
Daniel
8d753a482c Merge pull request #7 from prayag17/cssEditor
Organize the code
2020-12-01 15:32:12 +01:00
Prayag
cdd488c655 Use number instead of slider for bg blur and border radius & remove some over lapping code 2020-12-01 19:49:15 +05:30
Prayag
99eed0d4d7 Clean/organize the code 2020-12-01 19:42:41 +05:30
Prayag
1f736cb6c2 Merge pull request #1 from danieladov/patch-1
Fix Syntax errors
2020-12-01 17:53:41 +05:30
Prayag
a6a8435eb3 Fix Syntax Error 2020-12-01 17:51:12 +05:30
Mister Rajoy
98baca7927 Fix JSON syntax 2020-12-01 11:55:29 +01:00
Daniel
70c16248d4 Merge pull request #6 from prayag17/cssEditor
New features
2020-12-01 11:52:24 +01:00
Daniel
5e0a6f66b3 Fix Syntax errors 2020-11-30 12:46:01 +01:00
Prayag
cf73e6bafc Update my skins 2020-11-30 15:35:11 +05:30
Prayag
b2cc79d9df added links to slider css 2020-11-30 15:33:52 +05:30
Prayag
0ea8e6fec5 Create bgBlur.css 2020-11-30 15:32:36 +05:30
Prayag
d858ca509d Create border-radius.css 2020-11-30 15:24:53 +05:30
Prayag
60f353acd6 Create a new option name custom to customize jellyfin look 2020-11-30 15:23:34 +05:30
Mister Rajoy
122a4585fa Add sliders support 2020-11-25 13:37:00 +01:00
Mister Rajoy
61b39924b1 Update skins-3.0.json 2020-11-25 11:32:45 +01:00
Mister Rajoy
446ba43add Update configurationpage.html 2020-11-24 18:05:54 +01:00
Mister Rajoy
50b5480ce4 Update skins-3.0.json 2020-11-23 15:13:11 +01:00
Mister Rajoy
091d690ce4 Update skins-3.0.json 2020-11-22 02:08:11 +01:00
Mister Rajoy
e9fa65e407 Update skins-3.0.json 2020-11-22 01:40:54 +01:00
Mister Rajoy
68232e79ee Update skins-3.0.json 2020-11-22 01:23:16 +01:00
Mister Rajoy
e118d85259 Update skins-3.0.json 2020-11-22 01:15:14 +01:00
Mister Rajoy
f50afd93bf Update skins-3.0.json 2020-11-22 01:06:41 +01:00
Mister Rajoy
5569a04bd5 Update skins-3.0.json 2020-11-22 00:58:52 +01:00
Mister Rajoy
b9f8a53835 Update skins-3.0.json 2020-11-22 00:55:51 +01:00
Mister Rajoy
2b367476e5 Update skins-3.0.json 2020-11-22 00:48:10 +01:00
Daniel
20ef67df8d Update README.md 2020-11-13 15:54:54 +01:00
Mister Rajoy
e8ef129c52 Update configurationpage.html 2020-11-13 15:26:52 +01:00
Mister Rajoy
4671bcfea1 Update skins-3.0.json 2020-11-13 15:02:30 +01:00
Mister Rajoy
c254a29dd5 Update skins-3.0.json 2020-11-13 14:18:54 +01:00
Mister Rajoy
9cef7fead3 Update skins-3.0.json 2020-11-13 14:08:45 +01:00
Mister Rajoy
ba8467328b Update skins-3.0.json 2020-11-13 13:51:06 +01:00
Mister Rajoy
aa76f20398 Update skins-3.0.json 2020-11-13 13:24:39 +01:00
Mister Rajoy
d21d34c7e9 Update skins-3.0.json 2020-11-13 13:20:17 +01:00
Mister Rajoy
680d8120f3 Update skins-3.0.json 2020-11-13 12:50:25 +01:00
Mister Rajoy
79c4b736f2 Update skins-3.0.json 2020-11-13 12:19:25 +01:00
Mister Rajoy
e399488038 Update skins-3.0.json 2020-11-13 11:01:44 +01:00
Mister Rajoy
2bf9b79105 Update skins-3.0.json 2020-11-13 00:53:09 +01:00
Mister Rajoy
ee2bae7c93 Update skins-3.0.json 2020-11-13 00:45:06 +01:00
Mister Rajoy
9b6f9de69b Update skins-3.0.json 2020-11-13 00:40:33 +01:00
Mister Rajoy
3333fcae85 Update skins-3.0.json 2020-11-13 00:33:10 +01:00
Mister Rajoy
8a27eefbdb Update skins-3.0.json 2020-11-10 23:53:21 +01:00
Mister Rajoy
0dd8f485df Update skins-3.0.json 2020-11-10 23:34:34 +01:00
Mister Rajoy
9034cd0450 Update skins-3.0.json 2020-11-10 23:27:39 +01:00
Mister Rajoy
6d51f2ae6a Update skins-3.0.json 2020-11-10 19:23:02 +01:00
Mister Rajoy
be974af9b6 Update skins-3.0.json 2020-11-10 19:07:22 +01:00
Mister Rajoy
f1d3ccf27b Update skins-3.0.json 2020-11-10 19:04:24 +01:00
Mister Rajoy
a6be65e591 new JSON file 2020-11-10 18:50:09 +01:00
Mister Rajoy
13d37ce6f0 Add css editor 2020-11-10 18:40:10 +01:00
Daniel
609763b281 Merge pull request #4 from CTalvio/master
Add a couple typical presets for add-ons
2020-11-09 23:31:48 +01:00
Casper Talvio
5357ab3c1c Update skins-2.0.json 2020-11-10 00:08:43 +02:00
Casper Talvio
a31f13816f Update skins-2.0.json 2020-11-10 00:07:35 +02:00
Casper Talvio
d1a3dbc74f Update skins-2.0.json 2020-11-10 00:03:51 +02:00
Casper Talvio
39c1d9d4ff Update skins-2.0.json 2020-11-09 23:21:20 +02:00
Mister Rajoy
07753bf356 Merge branch 'master' of https://github.com/danieladov/jellyfin-plugin-skin-manager 2020-11-09 16:28:37 +01:00
Mister Rajoy
92fe6a35ff update to support skin versions 2020-11-09 16:25:42 +01:00
Daniel
67f4031630 Merge pull request #3 from danieladov/SkinVersions
Add support to kin versions
2020-11-09 16:13:42 +01:00
Daniel
c7c2608e03 Update skins.json 2020-11-09 16:13:03 +01:00
Mister Rajoy
560a52a195 Create skins-2.0.json 2020-11-09 16:10:15 +01:00
Mister Rajoy
b383eb88bb Update skins.json 2020-11-09 15:53:42 +01:00
Mister Rajoy
fee1323b9b Update skins.json 2020-11-09 14:23:28 +01:00
Mister Rajoy
e3f2b68e14 Update skins.json 2020-11-09 14:15:42 +01:00
Mister Rajoy
403444fadb Add default Skin 2020-11-09 13:31:26 +01:00
Daniel
000077c265 Update README.md 2020-11-08 20:56:08 +01:00
Daniel
6b92c15c13 Update README.md 2020-11-08 18:21:59 +01:00
Daniel
be1bb73005 Update README.md 2020-11-08 18:21:32 +01:00
Daniel
26758cec7d Update README.md 2020-11-08 18:21:08 +01:00
11 changed files with 912 additions and 115 deletions

View File

@@ -1,126 +1,312 @@
<!DOCTYPE html>
<html>
<head>
<title>Skin Manager</title>
</head>
<body>
<div data-role="page" class="page type-interior pluginConfigurationPage tbsConfigurationPage"
data-require="emby-input,emby-button">
<div data-role="content">
<div class="content-primary">
<form class="tbsConfigurationPage">
<div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">Skin Manager</h2>
<a is="emby-linkbutton" class="raised button-alt headerHelpButton emby-button" target="_blank"
href="https://github.com/danieladov/jellyfin-plugin-themesongs">Help</a>
</div>
<div class="verticalSection">
<p>
Select the skin you want to install and press Set Skin
</p>
<br />
</div>
<div class="selectContainer">
<label for="css">css</label>
<select is="emby-select" id="cssOptions">
</select>
<br />
<button is="emby-button" type="button" class="raised block" id="refresh-library"
onclick=setSkin()>
<span>Set Skin</span>
</button>
</form>
<div data-role="page" class="page type-interior pluginConfigurationPage tbsConfigurationPage" data-require="emby-input,emby-button">
<div data-role="content">
<div class="content-primary">
<form class="tbsConfigurationPage">
<div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">Skin Manager</h2>
<a is="emby-linkbutton" class="raised button-alt headerHelpButton emby-button" target="_blank" href="https://github.com/danieladov/jellyfin-plugin-skin-manager">Help</a>
</div>
<div class="verticalSection">
<p>
Select the skin you want to install and click Set Skin
</p>
<br>
</div>
<div class="allOptions">
<div class="selectContainer">
<label for="css">Skin</label>
<select is="emby-select" id="cssOptions" onchange="updateSelectors()"></select>
<br>
<div class="fieldDescription" id="description"></div>
</div>
</div>
<script type="text/javascript">
function loadSkins(){
$.getJSON('https://raw.githubusercontent.com/danieladov/jellyfin-plugin-skin-manager/master/skins.json', function(data) {
var cssOptions = document.getElementById("cssOptions");
data.forEach(element => {
var opt = document.createElement("option");
opt.appendChild(document.createTextNode(element.name));
opt.value=element.css;
cssOptions.appendChild(opt);
});
});
}
loadSkins();
function setSkin() {
ApiClient.getServerConfiguration().then(function (config) {
ApiClient.updateServerConfiguration(config).then(function() {
ApiClient.getNamedConfiguration('branding').then(function(brandingConfig) {
brandingConfig.CustomCss = $('#cssOptions').val();
ApiClient.updateNamedConfiguration('branding', brandingConfig).then(function () {
Dashboard.processServerConfigurationUpdateResult();
window.location.reload(true);
});
});
});
});
<div class="checkboxList checkboxList-verticalwrap" id ="options"></div>
<br>
</div>
<button is="emby-button" type="button" class="raised block" id="refresh-library" onclick=setSkin()>
<span>Set Skin</span>
</button>
</form>
</div>
</div>
<script type="text/javascript">
var data;
Dashboard.showLoadingMsg();
$.getJSON('https://raw.githubusercontent.com/danieladov/jellyfin-plugin-skin-manager/cssEditor/skins-3.0.json', function(json) {
data=json;
loadSkins();
Dashboard.hideLoadingMsg();
});
function loadSkins(){
var cssOptions = document.getElementById("cssOptions");
var skinVersions = document.getElementById("skinVersions");
var versionDescription = document.getElementById("versionDescription");
data.forEach(element => {
var opt = document.createElement("option");
opt.appendChild(document.createTextNode(element.name));
opt.value=element.defaultCss;
cssOptions.appendChild(opt);
});
updateSelectors()
}
</script>
function loadOptions(skin){
var options = skin.options;
var page = $.mobile.activePage;
var html = "";
html += '<div data-role="controlgroup">';
options.forEach(element=>{
if(element.type == "checkBox"){
html += getCheckBox(element);
}else if(element.type == "colorPicker"){
html += getColorPicker(element);
}else if(element.type == "number"){
html += getNumber(element);
}else if(element.type == "selector"){
html += getSelector(element);
}else if(element.type == "slider"){
html += getSlider(element);
}
});
html += loadPreviews(skin);
html += '</div>';
$('#options', page).html(html).trigger('create');
}
<script type="text/javascript">
var plugin = {
guid: 'e9ca8b8e-ca6d-40e7-85dc-58e536df8eb3'
};
function loadPreviews(skin){
if(skin.previews == undefined){
return "";
}
var html = "";
html += '<h2 class="sectionTitle" >Previews</h2>';
skin.previews.forEach(element => {
html += getImage(element.url);
html += getImgnames(element.name);
});
return html;
}
$('#configPage').on('pageshow', function () {
Dashboard.showLoadingMsg();
loadSavedConfig();
ApiClient.getPluginConfiguration(plugin.guid).then(function (config) {
$('#cssOptions').val(config.selectedCss).change();
Dashboard.hideLoadingMsg();
function getCheckBox ( option) {
var html = "";
var id = "chkFolder" ;
var name = option.name;
var css = option.css;
var description = option.description;
//html += '<label><input is="emby-checkbox" class="chkLibrary" type="checkbox" data-mini="true" id="' + id + '" name="' + id + '" data-value="' + value + '" '+' /><span>' + name + '</span></label>';
html += '<div class="checkboxContainer checkboxContainer-withDescription"><label><input class = "checkbox" type="checkbox" is="emby-checkbox" id="' + id + '"name="' + id + '" data-css="' + css + '" '+' /><span>'+ name +'</span></label><div class="fieldDescription checkboxFieldDescription">'+description+'</div></div>'
return html;
}
function getColorPicker ( option) {
var html = "";
var id = "favcolor" ;
var name = option.name;
var defaultValue = option.default;
var css = option.css;
var description = option.description;
var mode = option.mode;
html += '<div class="inputContainer"><input style="height: 1em; padding: 0px; border: none;" type=color class = "color" value="' + defaultValue + '"data-css = "'+ css+ '" data-mode="'+mode+'" id="' + id + '" name="' + id + '" label="'+name +'" /><div class="fieldDescription">'+description+'</div></div>';
return html;
}
function getNumber(option){
var html = "";
var id = "number" ;
var name = option.name;
var css = option.css;
var step = option.step==undefined?1:option.step;
var defaultValue = option.default;
var description = option.description;
//html += '<label for=number><input is="emby-input" type=number value=' + defaultValue + ' class = "number" data-css = "'+ css+ '" + data-mini="true" id="' + id + '" name="' + id + '" data-name="' + name + '" ' + ' /><span>' + name + '</span></label><br>';
html += '<div class="inputContainer"><input is="emby-input" type="number" class = "number" value=' + defaultValue + ' step=' + step + ' data-css = "'+ css+ '" id="' + id + '" name="' + id + '" min="0" max="300" label="'+name +'" /><div class="fieldDescription">'+description+'</div></div>'
return html;
}
function getSelector(option){
var html = "";
var id = "selector" ;
var name = option.name;
var css = option.css;
var defaultValue = option.default;
var description = option.description;
//html += '<label for=number><input is="emby-input" type=number value=' + defaultValue + ' class = "number" data-css = "'+ css+ '" + data-mini="true" id="' + id + '" name="' + id + '" data-name="' + name + '" ' + ' /><span>' + name + '</span></label><br>';
html += '<div class="selectContainer"><select is="emby-select" data-css= "'+css + '"class="selector" label="'+name+'">' + getOptions(option)+'</select></div>'
return html;
}
function getOptions(option){
var html = "";
var selections = option.selections
var css = option.css;
selections.forEach(element=>{
var name = element.name;
html+= '<option data-css= "'+css + '"value='+name+'>'+ name +'</option>'
})
return html;
}
function getSlider(option){
var html = "";
var id = "slider" ;
var name = option.name;
var css = option.css;
var step = option.step==undefined?1:option.step;
var defaultValue = option.default;
var description = option.description;
html += '<div class="inputContainer"><input is="emby-slider" type="range" class = "slider" value=' + defaultValue + ' step=' + step + ' data-css = "'+ css+ '" id="' + id + '" name="' + id + '" min="0" max="300" label="'+name +'" /><div class="fieldDescription">'+description+'</div></div>'
return html
}
function getImage(url){
var html = "";
html += '<fieldset class="verticalSection verticalSection-extrabottompadding"><img src="'+url+'">';
return html;
}
function getImgnames(name){
var html = "";
html += '<legend>'+name+'</legend></fieldset>';
return html;
}
function createCss(){
var savedHtml = "";
//process checkbox
var css = $('#cssOptions').val();
savedHtml += document.getElementById("cssOptions").innerHTML;
var checkboxes = document.getElementsByClassName("checkbox");
for (let element of checkboxes) {
savedHtml += element.innerHTML;
}
var selectedOptions = $('.checkbox:checked').map(function () {
return this.getAttribute('data-css');
}).get();
selectedOptions.forEach(element => {
css += element +"\n";
});
//proccess selector
var selectors = document.getElementsByClassName("selector");
for (let element of selectors) {
css += element.getAttribute("data-css").replaceAll("$",element.value) + "\n";
savedHtml += element.outerHTML;
}
//process colorPicker
selectedOptions.forEach(element=>{
css += element + "\n";
})
var colorPickers = document.getElementsByClassName("color");
for (let element of colorPickers) {
savedHtml += element.outerHTML
if(element.getAttribute("data-mode")=="rgba"){
var rgbColor = hexToRgb( element.value);
color = rgbColor.r + "," +rgbColor.g +"," + rgbColor.b;
} else{
color=element.value;
}
css+= element.getAttribute("data-css").replaceAll("$",color)+ "\n";
}
//procces number selector
var numberSelectors = document.getElementsByClassName("number");
for (let element of numberSelectors) {
savedHtml += element.outerHTML;
css+= element.getAttribute("data-css").replaceAll("$",element.value) + "\n";
}
//procces slider
var sliders = document.getElementsByClassName("slider");
for (let element of sliders) {
css+= element.getAttribute("data-css").replaceAll("$",element.value) + "\n";
}
return css;
}
function updateSelectors(){
var selected = document.getElementById("cssOptions");
var description = document.getElementById("description");
data.forEach(element=>{
if(element.name == selected.selectedOptions[0].innerText){
loadOptions(element);
description.innerHTML=element.description;
}
})
}
function setSkin() {
ApiClient.getServerConfiguration().then(function (config) {
ApiClient.updateServerConfiguration(config).then(function() {
ApiClient.getNamedConfiguration('branding').then(function(brandingConfig) {
brandingConfig.CustomCss = createCss();
ApiClient.updateNamedConfiguration('branding', brandingConfig).then(function () {
Dashboard.processServerConfigurationUpdateResult();
window.location.reload(true);
});
});
});
$('#configForm').on('submit', function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(plugin.guid).then(function (config) {
config.selectedCss = $('#cssOptions').val();
ApiClient.updatePluginConfiguration(plugin.guid, config).then(function (result) {
Dashboard.processPluginConfigurationUpdateResult(result);
});
});
return false;
});
</script>
});
}
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
</script>
<script type="text/javascript">
var plugin = {
guid: 'e9ca8b8e-ca6d-40e7-85dc-58e536df8eb3'
};
$('#configPage').on('pageshow', function () {
Dashboard.showLoadingMsg();
loadSavedConfig();
ApiClient.getPluginConfiguration(plugin.guid).then(function (config) {
$('#cssOptions').val(config.selectedCss).change();
Dashboard.hideLoadingMsg();
});
});
$('#configForm').on('submit', function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(plugin.guid).then(function (config) {
config.selectedCss = $('#cssOptions').val();
ApiClient.updatePluginConfiguration(plugin.guid, config).then(function (result) {
Dashboard.processPluginConfigurationUpdateResult(result);
});
});
return false;
});
</script>
<style>
img{
width: 100%;
}
fieldset.verticalSection.verticalSection-extrabottompadding {
border: 1px solid #333333;
border-radius: 10px;
}
legend {
font-size: 135%;
}
</style>
</div>
</body>
</html>
</html>

View File

@@ -3,8 +3,8 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<IsPackable>true</IsPackable>
<AssemblyVersion>1.3.0</AssemblyVersion>
<FileVersion>1.3.0</FileVersion>
<AssemblyVersion>1.4.0</AssemblyVersion>
<FileVersion>1.4.0</FileVersion>
<Authors />
<Company />
</PropertyGroup>

BIN
Kaleidochromic/Login.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
Monochromic/Lib.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
Monochromic/login.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@@ -1,4 +1,4 @@
<h1 align="center">Jellyfin Theme Songs Plugin</h1>
<h1 align="center">Jellyfin Skin Manager Plugin</h1>
<h3 align="center">Part of the <a href="https://jellyfin.media">Jellyfin Project</a></h3>
<p align="center">
@@ -6,8 +6,26 @@ Jellyfin Skin Manager is a plugin that helps you to download and install skins;
</p>
## Install Process
## From Repository
1. In jellyfin, go to dashboard -> plugins -> Repositories -> add and paste this link https://raw.githubusercontent.com/danieladov/JellyfinPluginManifest/master/manifest.json
2. Go to Catalog and search for Skin Manager
3. Click on it and install
4. Restart Jellyfin
## From .zip file
1. Download the .zip file from release page.
2. Extract it and place the .dll file in a folder called ```plugins/SkinManager``` under the program data directory or inside the portable install directory.
3. Restart Jellyfin.
## User Guide
1. Go to Plugins, click on Skin Manager.
2. Select the skin you want to install.
3. Click set skin.
## Build Process
@@ -20,3 +38,37 @@ dotnet publish --configuration Release --output bin
4. Place the resulting .dll file in a folder called ```plugins/SkinManager``` under the program data directory or inside the portable install directory
## Using with reverse proxy
When using the Nginx Reverse proxy config from the [Jellyfin docs](https://jellyfin.org/docs/general/networking/nginx.html) the theme might not work by default. (If you are using the subpath config, you can ignore all this.)
Because the config includes Content-Security-Policy which reduces risk of XSS, you need to add the URL from the skin repo and the fonts to the list of allowed external sources.
For example to use Kaleidochromic you need to do [this](https://github.com/CTalvio/Kaleidochromic/blob/main/README.md#using-with-reverse-proxy)
## JSON
## Skin Properties
- name //The name of the skin
- author //The author of the skin
- defaultCss //The base css of the skin
- options //An array of options that will modified the skin
- ## Options Properties
- type //the type of the input (checkBox, number, select, colorPicker)
- name // the name of the option
- description // the description of the option
- css //The css code that will modified the skin $ symbols in this code will be replaced by the value selected by the user (in number, select and color picer)
Some option have custom properties:
- ## number properties
- default //Default value
- step //step of the input
- ## selector properties
- selections //Array of options
- ## selections properties
- name // name of the option
- value // value of the option

97
skins-2.0.json Normal file
View File

@@ -0,0 +1,97 @@
[
{
"name": "Default",
"author": "Jellyfin",
"versions": [
{
"name": "Default",
"description":"Default, stock, Jellyfin.",
"css": ""
}
]
},
{
"name": "Jellyflix",
"author": "prayagprajapati17",
"versions": [
{
"name": "Default",
"description":"A theme that aims to replicate the red and black look of Netflix. Theme is by prayag17.",
"css": "@import url(https://prayag17.github.io/JellyFlix/default.css);"
}
]
},
{
"name": "Monochromic",
"author": "EdgeMentality",
"versions": [
{
"name": "Default",
"description": "This theme aims to be minimalistic and somewhat muted in color. Add-ons and custom accent colors are possible, but not entirely supported by this plug-in. Visit the github of the theme for more information.",
"css": "@import url(https://ctalvio.github.io/Monochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css');"
},
{
"name": "Sharp corners",
"description": "No rounded corners.",
"css": "@import url(https://ctalvio.github.io/Monochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); :root {--rounding: 0px;}"
},
{
"name": "Accent color - blue",
"description": "Uses the default blue color for accents.",
"css": "@import url(https://ctalvio.github.io/Monochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); @import url('https://ctalvio.github.io/Monochromic/jfblue_style.css');"
},
{
"name": "Accent color - purple",
"description": "Uses a purple shade, also suited for Jellyfin.",
"css": "@import url(https://ctalvio.github.io/Monochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); @import url('https://ctalvio.github.io/Monochromic/jfpurple_style.css');"
},
{
"name": "Accent color - blue - sharp",
"description": "Uses the default blue color for accents. Sharp corners.",
"css": "@import url(https://ctalvio.github.io/Monochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); @import url('https://ctalvio.github.io/Monochromic/jfblue_style.css'); :root {--rounding: 0px;}"
},
{
"name": "Accent color - purple - sharp",
"description": "Uses a purple shade, also suited for Jellyfin. Sharp corners.",
"css": "@import url(https://ctalvio.github.io/Monochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); @import url('https://ctalvio.github.io/Monochromic/jfpurple_style.css'); :root {--rounding: 0px;}"
}
]
},
{
"name": "Kaleidochromic",
"author": "EdgeMentality",
"versions": [
{
"name": "Default",
"description": "This theme aims to be more colorful and minimalistic. Add-ons and custom accent colors are possible, but not entirely supported by this plug-in. Visit the github of the theme for more information.",
"css": "@import url(https://ctalvio.github.io/Kaleidochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css');"
},
{
"name": "Sharp corners",
"description": "No rounded corners.",
"css": "@import url(https://ctalvio.github.io/Kaleidochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); :root {--rounding: 0px;}"
},
{
"name": "Accent color - blue",
"description": "Uses the default blue color for accents.",
"css": "@import url(https://ctalvio.github.io/Kaleidochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); @import url('https://ctalvio.github.io/Monochromic/jfblue_style.css');"
},
{
"name": "Accent color - blue - sharp",
"description": "Uses the default blue color for accents. Sharp corners.",
"css": "@import url(https://ctalvio.github.io/Kaleidochromic/default_style.css); @import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css'); @import url('https://ctalvio.github.io/Monochromic/jfblue_style.css'); :root {--rounding: 0px;}"
}
]
},
{
"name": "JellySkin",
"author": "prayagprajapati17",
"versions": [
{
"name": "Default",
"description":"A very bright and colorful look using lots of drop shadows. Theme is by prayag17.",
"css": "@import url('https://prayag17.github.io/JellySkin/default.css');"
}
]
}
]

373
skins-3.0.json Normal file
View File

@@ -0,0 +1,373 @@
[
{
"name": "Default",
"author": "Jellyfin",
"description": "Default, stock, Jellyfin.",
"defaultCss": "",
"options": [],
"previews":[
{
"name": "Login Page",
"url": ""
},
{
"name": "Home/Index Page",
"url": ""
},
{
"name": "Library Page",
"url": ""
},
{
"name": "Title page",
"url": ""
}
]
},
{
"name": "JellyFlix",
"author": "prayagprajapati17",
"description": "A theme that aims to replicate the red and black look of Netflix. Theme is by prayag17.",
"defaultCss": "@import url(https://prayag17.github.io/JellyFlix/default.css);",
"options": [],
"previews":[
{
"name": "Login Page",
"url": "https://github.com/prayag17/JellyFlix/raw/main/Public%20Ver%201/LoginMan.png?raw=true"
},
{
"name": "Home/Index Page",
"url": "https://github.com/prayag17/JellyFlix/raw/main/Public%20Ver%201/Home.png?raw=true"
},
{
"name": "Library Page",
"url": "https://github.com/prayag17/JellyFlix/raw/main/Public%20Ver%201/LibPage.png?raw=true"
},
{
"name": "Title page",
"url": "https://github.com/prayag17/JellyFlix/raw/main/Public%20Ver%201/TV-TitlePage.png?raw=true"
}
]
},
{
"name": "Monochromic",
"author": "EdgeMentality",
"description": "This theme aims to be minimalistic and somewhat muted in color. Add-ons and custom accent colors are possible, but not entirely supported by this plug-in. Visit the github of the theme for more information.",
"defaultCss": "@import url('https://ctalvio.github.io/Monochromic/default_style.css');",
"options": [
{
"type": "checkBox",
"name": "Improve performance",
"description": "The theme uses mask-image to fade out items below the top bar as you scroll. This works well on most reasonable hardware but struggles on some phones and especially smart TVs. This switches to a method without using mask-image, but foregoes the fade-out effect. I may switch to this method being the default.",
"css": "@import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css');"
},
{
"type": "checkBox",
"name": "No rounded corners",
"description": "In fact, squares off every rounded corner JF ever had.",
"css": "@import url('https://ctalvio.github.io/Monochromic/sharp_style.css'); "
},
{
"type": "checkBox",
"name": "Restore bottom bar style episode progress",
"description": "Don't like my transparent view progress overlay? Use this to go back to the old style.",
"css": "@import url('https://ctalvio.github.io/Monochromic/bottom-progress_style.css');"
},
{
"type": "number",
"name": "Modify rounding",
"description": "Amount of rounding. Zero is none.",
"css": ":root {--rounding: $px;}",
"default": "5"
},
{
"type": "colorPicker",
"name": "Accent color",
"description": "Choose a custom accent color to use with the theme.",
"css": "@import url('https://ctalvio.github.io/Monochromic/customcolor_style.css');:root {--accent: $;}",
"default": ""
}
],
"previews":[
{
"name": "Login Page",
"url": "https://github.com/prayag17/jellyfin-plugin-skin-manager/blob/cssEditor/Monochromic/login.jpg?raw=true"
},
{
"name": "Home/Index Page",
"url": "https://github.com/CTalvio/Monochromic/blob/master/screenshots/1.png?raw=true"
},
{
"name": "Library Page",
"url": "https://github.com/prayag17/jellyfin-plugin-skin-manager/blob/cssEditor/Monochromic/Lib.jpg?raw=true"
},
{
"name": "Title page",
"url": "https://github.com/CTalvio/Monochromic/raw/master/screenshots/2.png"
}
]
},
{
"name": "Kaleidochromic",
"author": "EdgeMentality",
"description": "This theme aims to be more colorful and minimalistic. Add-ons and custom accent colors are possible, but not entirely supported by this plug-in. Visit the github of the theme for more information.",
"defaultCss": "@import url('https://ctalvio.github.io/Kaleidochromic/default_style.css');",
"options": [
{
"type": "checkBox",
"name": "Improve performance",
"description": "The theme uses mask-image to fade out items below the top bar as you scroll. This works well on most reasonable hardware but struggles on some phones and especially smart TVs. This switches to a method without using mask-image, but foregoes the fade-out effect.",
"css": "@import url('https://ctalvio.github.io/Monochromic/improve-performance_style.css');"
},
{
"type": "checkBox",
"name": "Restore bottom bar style episode progress",
"description": "Don't like my transparent view progress overlay? Use this to go back to the old style.",
"css": "@import url('https://ctalvio.github.io/Monochromic/bottom-progress_style.css');"
},
{
"type": "number",
"name": "Modify rounding",
"description": "Amount of rounding. Zero is none.",
"css": ":root {--rounding: $px;}",
"default": "12"
},
{
"type": "colorPicker",
"name": "Accent color",
"description": "Choose a custom accent color to use with the theme.",
"css": ":root {--accent: $;}",
"default": "#6279cd"
}
],
"previews":[
{
"name": "Login Page",
"url": "https://github.com/prayag17/jellyfin-plugin-skin-manager/blob/cssEditor/Kaleidochromic/Login.jpg?raw=true"
},
{
"name": "Home/Index Page",
"url": "https://github.com/CTalvio/Kaleidochromic/raw/main/screenshots/6.png"
},
{
"name": "Library Page",
"url": "https://github.com/CTalvio/Kaleidochromic/raw/main/screenshots/5.png"
},
{
"name": "Title page",
"url": "https://github.com/CTalvio/Kaleidochromic/raw/main/screenshots/1.png"
}
]
},
{
"name": "Novachromic",
"author": "EdgeMentality",
"description": "Novachromic is essentially Monochromic, but with another layer of overrides on top.",
"defaultCss": "@import url('https://ctalvio.github.io/Novachromic/default_style.css');",
"previews": [
{
"name": "Home/Index Page",
"url": "https://github.com/CTalvio/Novachromic/raw/main/screenshots/one.png"
},
{
"name": "Library Page",
"url": "https://github.com/CTalvio/Novachromic/raw/main/screenshots/six.png"
},
{
"name": "Title page",
"url": "https://github.com/CTalvio/Novachromic/raw/main/screenshots/four.png"
},
{
"name": "Dashboard page",
"url": "https://github.com/CTalvio/Novachromic/raw/main/screenshots/two.png"
}
],
"options": [
{
"type": "checkBox",
"name": "Restore bottom bar style episode progress",
"description": "Don't like my transparent view progress overlay? Use this to go back to the old style.",
"css": "@import url('https://ctalvio.github.io/Monochromic/bottom-progress_style.css');"
},
{
"type": "number",
"name": "Modify rounding",
"description": "Amount of rounding. Zero is none.",
"css": ":root {--rounding: $px;}",
"default": "12"
},
{
"type": "colorPicker",
"name": "Accent color",
"description": "Choose a custom accent color to use with the theme.",
"css": ":root {--accent: $;}",
"default": "#ffffff"
}
]
},
{
"name": "JellySkin",
"author": "prayagprajapati17",
"description": "A very bright and colorful look using lots of drop shadows. Theme is by prayag17.",
"defaultCss": "@import url('https://prayag17.github.io/JellySkin/default.css');",
"options": [
{
"type": "checkBox",
"name": "Sea Gradient",
"description": "changes the Jellyfin themed Hover gradient",
"css": "@import url('https://prayag17.github.io/JellySkin/seaGradient.css');"
},
{
"type": "checkBox",
"name": "Sunset Gradient",
"description": "changes the Jellyfin themed Hover gradient",
"css": "@import url('https://prayag17.github.io/JellySkin/sunsetGradient.css');"
},
{
"type": "checkBox",
"name": "Night Sky Gradient",
"description": "changes the Jellyfin themed Hover gradient",
"css": "@import url('https://prayag17.github.io/JellySkin/nightSkyGradient.css');"
},
{
"type": "checkBox",
"name": "Morning Gradient",
"description": "changes the Jellyfin themed Hover gradient",
"css": "@import url('https://prayag17.github.io/JellySkin/morningGradient.css');"
}
],
"previews":[
{
"name": "Login Page",
"url": "https://github.com/prayag17/JellySkin/raw/master/Version%204/Login.png?raw=true"
},
{
"name": "Home/Index Page",
"url": "https://github.com/prayag17/JellySkin/raw/master/Version%204/Home.png?raw=true"
},
{
"name": "Library Page",
"url": "https://github.com/prayag17/JellySkin/raw/master/Version%204/lib%202.png?raw=true"
},
{
"name": "Title page",
"url": "https://github.com/prayag17/JellySkin/raw/master/Version%204/title%201.png?raw=true"
}
]
},
{
"name": "Custom",
"author": "you",
"description": "customize the look of jellyfin by your needs",
"defaultCss": "",
"options": [
{
"type": "selector",
"name": "Change Font",
"description": "Change the default fonts",
"css": "html {font-family: $,sans-serif ; } body,h1,h2,h3 { font-family:$ ,sans-serif;} @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,800;1,900&display=swap');",
"selections": [
{
"name": "Noto Sans"
},
{
"name": "Times New Roman"
},
{
"name": "Arial"
},
{
"name": "Helvetica"
},
{
"name": "Times"
},
{
"name": "Courier New"
},
{
"name": "Verdana"
},
{
"name": "Courier"
},
{
"name": "Arial Narrow"
},
{
"name": "Candara"
},
{
"name": "Poppins"
}
]
},
{
"type": "number",
"name": "Title Font Size",
"description": "Change the size of the font used at titles.",
"step": "0.1",
"css": "h1 {font-size: $em;}",
"default": "1.8"
},
{
"type": "colorPicker",
"mode":"rgba",
"name": "Accent color",
"description": "Choose a custom accent color to use with the theme.",
"css": ".countIndicator {background: rgba($,0.8);}.playedIndicator, .innerCardFooter /*Accenting*/.button-flat:hover {background: rgba($,0.25);}.paper-icon-button-light:hover { background-color: rgba($,0.25) !important;}.subtitleappearance-preview { background: linear-gradient(140deg,rgba($),#111) !important;}.navMenuOption-selected, .selectionCommandsPanel { background: rgba($, 0.8) !important;}.raised,.fab,a[data-role='button'] { background: rgba($, 0.8) !important;\ttransition: all 0.2s !important;} /*Glow accent*/ .raised.homeLibraryButton {box-shadow: 0px 0px 5px rgba($, 0) !important; border: solid 1px rgba($,0) !important;}.cardOverlayContainer:hover,.dialog,..raised.homeLibraryButton:hover { box-shadow: 0px 0px 5px rgb($) !important; border: solid 1px rgba($,0.6) !important;}.cardOverlayContainer { border: solid 1px rgba($,0.0) !important;}"
},
{
"type": "colorPicker",
"mode": "hex",
"name": "Console Panel Color",
"description": "Modifies the color of the left menu panel.",
"css": ".mainDrawer-scrollContainer { color: $; }",
"default":"#ffffff"
},
{
"type": "checkBox",
"name": "Enlarge Tab Buttons",
"description": "Enlarges the tab buttons, suggested, genres, etc. By default they are really tiny, especially on mobile.",
"css": ".headerTabs.sectionTabs {text-size-adjust: 110%; font-size: 110%;}.pageTitle {margin-top: auto; margin-bottom: auto;}.emby-tab-button {padding: 1.75em 1.7em;}"
},
{
"type": "checkBox",
"name": "Stylized Episode Previews",
"description": "The episode previews in season view are sized based on horizontal resolution. This leads to a lot of wasted space on the episode summary and a high vertical page, which requires a lot of scrolling. This code reduces the height of episode entries, which solves both problems.",
"css": "/* Size episode preview images in a more compact way */.listItemImage.listItemImage-large.itemAction.lazy {height: 110px;}.listItem-content {height: 115px;}.secondary.listItem-overview.listItemBodyText {height: 61px; margin: 0;}"
},
{
"type": "colorPicker",
"mode": "hex",
"name": "Custom Background Color",
"description": "Change background color.",
"css": ".backgroundContainer, .dialog, html { background-color: $;}",
"default": "#000000"
},
{
"type": "colorPicker",
"mode": "hex",
"name": "Right Header Color",
"description": "This modifies the colors of the cast, search and user buttons in the top right.",
"css": ".headerRight { color: $; }",
"default":"#ffffff"
},
{
"type": "number",
"name": "Border Radius",
"description": ":root {--rounding: 0px;}.formDialogHeader {border-top-left-radius: var(--rounding);border-top-right-radius: var(--rounding);}.formDialogFooter {border-bottom-left-radius: var(--rounding);border-bottom-right-radius: var(--rounding);}.cardOverlayContainer {border-radius: var(--rounding) !important;}.toast,.paperList,.cardContent,.sessionNowPlayingInnerContent, .listItem:hover, .cardImage,.fab,.multiSelectCheckboxOutline,.itemSelectionPanel,.cardContent-button, .cardContent-shadow, .itemDetailImage, .cardOverlayButton-hover,.cardImageContainer,.cardPadder,.listItemImage,.listItemImageButton,.listItemButton,.headerButton,.paper-icon-button-light,.innerCardFooter,.blurhash-canvas,.actionSheetMenuItem:hover,.dialog,.listItemIcon,.listItem-border,.button-flat,.visualCardBox,.checkboxOutline,.emby-select-withcolor,.chapterThumbTextContainer,.chapterThumbContainer,.chapterThumb,.emby-input, .emby-textarea, .emby-select-withcolor,.cardOverlayButtonIcon,.subtitleappearance-preview.flex.align-items-center.justify-content-center {border-radius: var(--rounding) !important;}.osdPoster img {border-radius: var(--rounding); border: none;}.mdl-slider::-moz-range-thumb {border-radius: var(--rounding);}.mdl-slider::-ms-thumb {border-radius: var(--rounding);}.mdl-slider::-webkit-slider-thumb {border-radius: var(--rounding);}div[data-role='controlgroup'] a[data-role='button']:first-child {border-bottom-left-radius: var(--rounding);border-top-left-radius: var(--rounding);}div[data-role='controlgroup'] a[data-role='button']:last-child {border-bottom-right-radius: var(--rounding);border-top-right-radius: var(--rounding);}",
"css": "",
"default":"0"
},
{
"type": "number",
"name": "Backdrop Blur",
"description": "adds blur to the backdrop images default is zero",
"css": ":root{--bgblur: blur($px)}.backdropImage {filter: var(--bgblur);}.backgroundContainer.withBackdrop {background-color: rgba(0,0,0,0);}",
"default": "0"
}
]
}
]

View File

@@ -1,4 +1,10 @@
[
{
"name":"Default",
"author":"Jellyfin",
"css": ""
},
{
"name":"Jellyflix",
"author":"prayagprajapati17",
@@ -24,4 +30,4 @@
"css": "@import url('https://prayag17.github.io/JellySkin/default.css');"
}
]
]

8
src/bgBlur.css Normal file
View File

@@ -0,0 +1,8 @@
:root{--bgblur: blur($px)}
/*Blur backdrops, feel free to edit the intensity of the filter values*/
.backdropImage {
filter: var(--bgblur);
}
.backgroundContainer.withBackdrop {
background-color: rgba(0,0,0,0);
}

75
src/border-radius.css Normal file
View File

@@ -0,0 +1,75 @@
/*Setting border Radius*/
:root {--rounding: 0px;}
/*Rounded corners on pretty much everything-Source Monochromic*/
.formDialogHeader {
border-top-left-radius: var(--rounding);
border-top-right-radius: var(--rounding);
}
.formDialogFooter {
border-bottom-left-radius: var(--rounding);
border-bottom-right-radius: var(--rounding);
}
.cardOverlayContainer {
border-radius: var(--rounding) !important;
}
.toast,
.paperList,
.cardContent,
.sessionNowPlayingInnerContent,
.listItem:hover,
.cardImage,
.fab,
.multiSelectCheckboxOutline,
.itemSelectionPanel,
.cardContent-button,
.cardContent-shadow,
.itemDetailImage,
.cardOverlayButton-hover,
.cardImageContainer,
.cardPadder,
.listItemImage,
.listItemImageButton,
.listItemButton,
.headerButton,
.paper-icon-button-light,
.innerCardFooter,
.blurhash-canvas,
.actionSheetMenuItem:hover,
.dialog,
.listItemIcon,
.listItem-border,
.button-flat,
.visualCardBox,
.checkboxOutline,
.emby-select-withcolor,
.chapterThumbTextContainer,
.chapterThumbContainer,
.chapterThumb,
.emby-input,
.emby-textarea,
.emby-select-withcolor,
.cardOverlayButtonIcon,
.subtitleappearance-preview.flex.align-items-center.justify-content-center {
border-radius: var(--rounding) !important;
}
.osdPoster img {
border-radius: var(--rounding); border: none;
}
.mdl-slider::-moz-range-thumb {
border-radius: var(--rounding);
}
.mdl-slider::-ms-thumb {
border-radius: var(--rounding);
}
.mdl-slider::-webkit-slider-thumb {
border-radius: var(--rounding);
}
div[data-role="controlgroup"] a[data-role="button"]:first-child {
border-bottom-left-radius: var(--rounding);
border-top-left-radius: var(--rounding);
}
div[data-role="controlgroup"] a[data-role="button"]:last-child {
border-bottom-right-radius: var(--rounding);
border-top-right-radius: var(--rounding);
}