<html>
<head>
<title>SXMO : Theme-o-matic</title>
<style type="text/css" media="screen">
@font-face {
font-family: 'nerdfont';
src: url('/theme-o-matic/Symbols-2048-em-Nerd-Font-Complete.woff2') format('woff2') ;
font-weight: 400;
font-style: normal;
}
#output_image {
object-fit: cover;
object-position: 50% 50%;
}
.colorpicktabname:hover {
border-top-color: #000000;
border-left-color: #000000;
border-right-color: #000000;
}
.colorpicktabname {
position:relative;
top: 0px;
height: 25px;
float:left;
background-color: #FFFFFF;
padding: 3px;
margin-right: 3px;
border: 2px;
font-weight: 700;
border-top-style: solid;
border-left-style: solid;
border-right-style: solid;
border-top-color: #FFFFFF;
border-left-color: #FFFFFF;
border-right-color: #FFFFFF;
}
.colorpicktabname-active {
background-color: #F0F0F0;
}
.colorpicktab {
background-color: #F0F0F0;
border-color: #000;
border: 0px;
border-style: solid;
position:absolute;
top: 0px;
width: 340px;
border-style: solid;
display: none;
padding: 10px;
}
.colorpick {
width: 60px;
}
.colorpickbox:hover{
background-color: #E0E0E0;
}
.lastfocused {
background-color: #c0c0c0;
}
body {
font-family: "sans";
}
.icon {
font-family: "nerdfont";
}
.dmenu-foreground{
color: #bbbbbb;
}
.dmenu-background{
background-color: #222222;
}
.dmenu-selforeground{
color: #eeeeee;
}
.dmenu-selbackground{
background-color: #005577;
}
.dmenu-selhighlightforeground:hover{
color: #ffc978;
}
.dmenu-selhighlightbackground:hover{
background-color: #005577;
}
.dmenu-highlightforeground:hover{
color: #ffc978;
}
.dmenu-highlightbackground:hover{
background-color: #222222;
}
.dmenu-outforeground{
color: #000000;
}
.dmenu-outbackground{
background-color: #00ffff;
}
.dwm-selforeground{
color: #eeeeee;
}
.dwm-selbackground{
background-color: #005577;
}
.dwm-foreground{
color: #bbbbbb;
}
.dwm-background{
background-color: #222222;
}
.desktop_box{
top: 0px;
}
.layout_box{
top: 0px;
}
</style>
<script src="https://tetrakist.srht.site/theme-o-matic/color-thief.umd.js"></script>
<script src="https://tetrakist.srht.site/theme-o-matic/vibrant.min.js"></script>
<script type"text/javascript">
const colorThief = new ColorThief();
function arrToHex(arr) {
let s = '#';
for (let i = 0; i < arr.length; i++) {
s += ((arr[i] / 16) | 0).toString(16);
s += ((arr[i] % 16) | 0).toString(16);
}
return s;
}
let rgb2hex= c=>'#'+c.match(/\d+/g).map(x=>(+x).toString(16).padStart(2,0)).join``;
let rgb2lum = function(c) {
rgbarr = c=>c.match(/\d+/g).map(x=>(+x));
rgbval = rgbarr(c);
return(Math.sqrt(Math.pow(rgbval[0],2)*0.299 + Math.pow(rgbval[1],2)*0.587 + Math.pow(rgbval[2],2)*0.114));
};
pickcolor = function(){
lastfocused.value = rgb2hex(this.style.backgroundColor);
lastfocused.rgb = this.style.backgroundColor;
lastfocused.dispatchEvent(new Event("change"));
};
async function makePalette(palette){
var vib_box = document.getElementById('vib_box');
while (vib_box.firstChild) { vib_box.removeChild(vib_box.firstChild); }
vib_palette = await Vibrant.from(img.src).quality(1).clearFilters().getPalette();
for (colorobj of ["DarkVibrant", "Vibrant", "LightVibrant", "DarkMuted", "Muted", "LightMuted"]){
var colorDiv = document.createElement('div');
colorDiv.className = 'color';
colorDiv.style.height = '30';
colorDiv.style.width = '100';
colorDiv.style.backgroundColor=vib_palette[colorobj].hex;
colorDiv.onclick = pickcolor;
vib_box.appendChild(colorDiv);
}
var ct_box = document.getElementById('ct_box');
while (ct_box.firstChild) { ct_box.removeChild(ct_box.firstChild); }
for (colorobj of palette){
var colorDiv = document.createElement('div');
colorDiv.className = 'color';
colorDiv.style.height = '45';
colorDiv.style.width = '45';
colorDiv.style.float = 'left';
colorDiv.style.align = 'center';
colorDiv.style.backgroundColor=arrToHex(colorobj);
colorDiv.onclick = pickcolor;
ct_box.appendChild(colorDiv);
}
}
// function preview_image() {
// var output = document.getElementById('output_image');
// var img_url = document.getElementById('image_url');
// output.src = img_url.value;
// }
function preview_image(event) {
var reader = new FileReader();
reader.onload = function(){
var output = document.getElementById('output_image');
output.src = reader.result;
}
reader.readAsDataURL(event.target.files[0]);
}
</script>
</head>
<body>
<h1>SXMO : Theme-o-matic</h1>
<hr>
Download and use on your own machine! No webserver needed! -- <a href="https://git.sr.ht/~anjan/theme-o-matic">Source code (MIT Licensed)</a>
<hr>
<div style="width:720px">
<div style="position:absolute; width: 360px;">
Upload Background Image:
<!-- <input type="text" id="image_url" name="image_url">
<input type="button" value="Load" onclick="preview_image()"> -->
<input type="file" accept="image/*" onchange="preview_image(event)"><br>
<input type="radio" id="scale" name="image_settings" checked><label for="scale">Scale</label>
<input type="radio" id="stretch" name="image_settings"><label for="stretch">Stretch</label>
<input type="radio" id="center" name="image_settings"><label for="center">Center</label>
<hr>
<b>Insta-Palette:</b><br>
Click a color to assign to selected resource:<br>
<!--div id="ct_box" style="position:relative; left: 0px; width: 225px"> </div-->
<!--div id="vib_box" style="position:relative; top: -180; left: 230px; width: 90"> </div-->
<div id="ct_box" style="position:relative; width: 225px; float:left"> </div>
<div id="vib_box" style="position:relative; width: 101px; float:left"> </div>
<br style="clear: both">
Custom color: <input type="color" id="custom_color" style="vertical-align:bottom;"> <br>
<span style="font-size:small">(Use eye-dropper tool to get pixel color.)</span>
<hr>
<div>
<input type="checkbox" id="show_menu" checked><label for="show_menu">Show Menu</label>
<input type="checkbox" id="show_statusbar" checked><label for="show_statusbar">Show Status Bar</label>
<input type="button" id="xr_export" value="Export .Xresources file">
<hr>
<b>X resource settings:</b><br>
Select resource configuration tab:<br>
<div class="colorpicktabnames">
<div class="colorpicktabname" id="dmenu-tabname" >dmenu</div>
<div class="colorpicktabname" id="dwm-tabname" style="position:relative; top: 0px; height: 25px;">dwm</div>
</div>
<div class="colorpicktabs" style="clear: both; position:relative;">
<div class="colorpicktab" id="dmenu-tab">
<input type="button" id="dmenu_reset_colors" value="Reset to defaults"><br><br>
<div class="colorpickbox">
<input class="colorpick" id=".dmenu-foreground" data-attr="color">
<label class="colorpicktext" for=".dmenu-foreground">dmenu.foreground</label>
</div>
<div class="colorpickbox">
<input class="colorpick" id=".dmenu-background" data-attr="background-color">
<label class="colorpicktext" for=".dmenu-background">dmenu.background</label>
</div>
<br>
<div class="colorpickbox">
<input class="colorpick" id=".dmenu-selforeground" data-attr="color">
<label class="colorpicktext" for=".dmenu-selforeground">dmenu.selforeground</label><br>
</div>
<div class="colorpickbox">
<input class="colorpick" id=".dmenu-selbackground" data-attr="background-color">
<label class="colorpicktext" for=".dmenu-selbackground">dmenu.selbackground</label><br>
</div>
<br>
<div class="colorpickbox">
<input class="colorpick" id=".dmenu-outforeground" data-attr="color">
<label class="colorpicktext" for=".dmenu-outforeground">dmenu.outforeground</label><br>
</div>
<div class="colorpickbox">
<input class="colorpick" id=".dmenu-outbackground" data-attr="background-color">
<label class="colorpicktext" for=".dmenu-outbackground">dmenu.outbackground</label><br>
</div>
<br>
<div class="colorpickbox">
<i>
<input class="colorpick" id=".dmenu-highlightforeground" data-attr="color">
<label class="colorpicktext" for=".dmenu-highlightforeground">dmenu.highlightforeground</label>*<br>
</i>
</div>
<div class="colorpickbox">
<i>
<input class="colorpick" id=".dmenu-highlightbackground" data-attr="background-color">
<label class="colorpicktext" for=".dmenu-highlightbackground">dmenu.highlightbackground</label>*<br>
</i>
</div>
<br>
<div class="colorpickbox">
<i>
<input class="colorpick" id=".dmenu-selhighlightforeground" data-attr="color">
<label class="colorpicktext" for=".dmenu-selhighlightforeground">dmenu.selhighlightforeground</label>*<br>
</i>
</div>
<div class="colorpickbox">
<i>
<input class="colorpick" id=".dmenu-selhighlightbackground" data-attr="background-color">
<label class="colorpicktext" for=".dmenu-selhighlightbackground">dmenu.selhighlightbackground</label>*<br>
</i>
</div>
</div> <!-- end colorpicktab -->
<div class="colorpicktab" id="dwm-tab">
<input type="button" id="dwm_reset_colors" value="Reset to defaults"><br><br>
<div class="colorpickbox">
<input class="colorpick" id=".dwm-foreground" data-attr="color">
<label class="colorpicktext" for=".dwm-foreground">dwm.foreground</label><br>
</div>
<div class="colorpickbox">
<input class="colorpick" id=".dwm-background" data-attr="background-color">
<label class="colorpicktext" for=".dwm-background">dwm.background</label><br>
</div>
<br>
<div class="colorpickbox">
<input class="colorpick" id=".dwm-selforeground" data-attr="color">
<label class="colorpicktext" for=".dwm-selforeground">dwm.selforeground</label><br>
</div>
<div class="colorpickbox">
<input class="colorpick" id=".dwm-selbackground" data-attr="background-color">
<label class="colorpicktext" for=".dwm-selbackground">dwm.selbackground</label><br>
</div>
</div> <!-- end colorpicktab -->
<i>*No visual feedback</i>
<br style="clear: both">
<br>
</div>
<div style="position:absolute; left: 360px; top: 0px; width: 360px; height: 720px; background-color: #082430;">
<div id="mockup_box" style="position: static">
<img id="output_image" height=720 width=360><br>
<div id="menu_container" style="position: static">
<div id="border_box" class="dmenu-selforeground dmenu-selbackground" style="position: absolute;"></div>
<div id="menu_box" style="position: absolute;"></div>
<div id="title_box" class="dmenu-selforeground dmenu-selbackground" style="position: absolute;"></div>
<form>
<input id="input_box" value="|" class="dmenu-foreground dmenu-background" style="position: absolute; border: none;">
</form>
</div>
<div id="statusbar_container" style="position: static">
<div id="statustext_box" class="statustext_box dwm-background dwm-foreground" style="position: absolute;"></div>
<div id="desktop1_box" class="desktop_box" style="position: absolute;"> 1 </div>
<div id="desktop2_box" class="desktop_box" style="position: absolute;"> 2 </div>
<div id="desktop3_box" class="desktop_box" style="position: absolute;"> 3 </div>
<div id="desktop4_box" class="desktop_box" style="position: absolute;"> 4 </div>
<div id="layout_box" class="layout_box" style="position: absolute;"> []= </div>
</div>
</div>
</div>
</div>
</body>
<script type"text/javascript">
imageheight = 720;
imagewidth = 360;
// menuheightpct = 60;
menuwidthpct = 60;
menutext = ["Scripts", "Apps", "Files", "Maps",
"Dialer" , "Texts", "Camera", "Networks",
"Audio", "Config", "Power", "Close Menu"];
menuicons = ["", "", "", '',
"" , "", "", "",
"", "", "⏻", ""];
menuitems = menutext.length;
menuslots = menuitems + 1;
titlebox = document.getElementById("title_box")
titlebox.innerHTML = "Sys ";
titlebox.padding = "2px";
itemheight = 20; // set this based on font height.
itemheight = titlebox.offsetHeight; // set this based on font height.
//menuheight = Math.floor(imageheight*menuheightpct/100);
menuheight = menuslots*itemheight;
menuwidth = Math.floor(imagewidth*menuwidthpct/100);
menutop = Math.floor(imageheight/2-menuheight/2);
menuleft = Math.floor(imagewidth/2-menuwidth/2);
menuborder = 3;
menuboxheight = menuheight+menuborder*2;
menuboxwidth = menuwidth+menuborder*2;
menuboxtop = menutop-menuborder;
menuboxleft = menuleft-menuborder;
titleboxtop = menutop;
titleboxleft = menuleft;
titleboxheight = itemheight;
mockup_box = document.getElementById("mockup_box");
document.getElementById("menu_box").style.cssText += "top: "+menutop+"; left: "+menuleft+"px; width: "+menuwidth+"px; height: "+menuheight+"px; " ;
document.getElementById("border_box").style.cssText += "top: "+menuboxtop+"; left: "+menuboxleft+"px; width: "+menuboxwidth+"px; height: "+menuboxheight+"px;" ;
titlebox.style.cssText += "top: "+titleboxtop+"; left: "+titleboxleft+"px; height: "+titleboxheight+"px;" ;
inputboxleft = titleboxleft + titlebox.offsetWidth;
inputboxwidth = menuwidth - titlebox.offsetWidth;
document.getElementById("input_box").style.cssText += "top: "+titleboxtop+"; left: "+inputboxleft+"px; width: "+inputboxwidth+"px; height: "+titleboxheight+"px;" ;
menu_container = document.getElementById('menu_container');
show_menu = document.getElementById('show_menu');
show_menu.onchange = function(){
menu_container.style.display = menu_container.style.display == "none" ? "block" : "none";
}
statusbar_container = document.getElementById('statusbar_container');
show_statusbar = document.getElementById('show_statusbar');
show_statusbar.onchange = function(){
statusbar_container.style.display = statusbar_container.style.display == "none" ? "block" : "none";
}
for(i = 1; i < menuslots; i++){
menuitem = document.createElement('div');
menuitem.style.top = menutop + i*itemheight;
menuitem.style.height = itemheight;
menuitem.style.left = menuleft;
menuitem.style.width = menuwidth;
menuitem.style.position = "absolute";
menuitem.classList.add('dmenu-foreground');
menuitem.classList.add('dmenu-background');
// menuitem.classList.add('dmenu-selforeground');
// menuitem.classList.add('dmenu-selbackground');
menuitem.onmouseout = function() {
this.classList.toggle("dmenu-selforeground");
this.classList.toggle("dmenu-selbackground");
}
menuitem.onmouseover = function() {
this.classList.toggle("dmenu-selforeground");
this.classList.toggle("dmenu-selbackground");
}
menuitem.onclick = function() {
this.classList.toggle("dmenu-outforeground");
this.classList.toggle("dmenu-outbackground");
}
menuitem.innerHTML = ' <span class="icon">' + menuicons[i-1] + "</span> " + menutext[i-1];
menu_container.appendChild(menuitem);
}
statusbartop = 0;
statusbarleft = 0;
statusbarwidth = imagewidth;
statusbarheight = titleboxheight;
document.getElementById("statustext_box").style.cssText += "top: "+statusbartop+"; left: "+statusbarleft+"px; width: "+statusbarwidth+"px; height: "+statusbarheight+"px;" ;
titlebox = document.getElementById("title_box")
titlebox.innerHTML = "Sys";
titlebox.padding = "2px";
desktop_boxen = document.getElementsByClassName("desktop_box")
desktop_boxen[0].style.left = 0+"px";
desktop_boxen[0].classList.add('dwm-selforeground');
desktop_boxen[0].classList.add('dwm-selbackground');
for(i=1; i < desktop_boxen.length; i++){
desktop_boxen[i].style.left = parseInt(desktop_boxen[i-1].style.left) + desktop_boxen[i-1].offsetWidth;
desktop_boxen[i].classList.add('dwm-foreground');
desktop_boxen[i].classList.add('dwm-background');
}
layout_box = document.getElementById("layout_box")
layout_box.style.left = parseInt(desktop_boxen[i-1].style.left) + desktop_boxen[i-1].offsetWidth;
status_text = "W H46 C85% ";
var currentTime = new Date ( );
var currentHours = currentTime.getHours ( );
var currentMinutes = currentTime.getMinutes ( );
var currentSeconds = currentTime.getSeconds ( )
currentHours = ( currentHours > 12 ) ? currentHours - 12 : currentHours;
currentMinutes = ( currentMinutes < 10 ? "0" : "" ) + currentMinutes;
var currentTimeString = currentHours + ":" + currentMinutes;
status_text += currentTimeString;
statustext_box = document.getElementById("statustext_box");
statustext_box.innerHTML = status_text;
statustext_box.style.left = 0;
statustext_box.style.width = imagewidth;
statustext_box.style.textAlign = "right";
rules = document.styleSheets[0].rules;
function getStyleRuleIndexBySelector(selector, prop){
var result = [], i,
value = (prop ? selector + "{" + prop + "}" : selector).replace(/\s/g, ''), // remove whitespaces
s = prop ? "cssText" : "selectorText";
for( i=0; i < rules.length; i++ )
if(rules[i][s] !== undefined){
if( rules[i][s].replace(/\s/g, '') == value)
result.push(i);
}
return result;
}
updateCSS = function(){
if(/^#([0-9A-F]{3}){1,2}$/i.test(this.value)){
console.log("valid RGB hex.");
rule_idx = getStyleRuleIndexBySelector(this.id)
rules[rule_idx[0]].style[this.dataset.attr] = this.value;
}
this.style.backgroundColor = this.value;
luminosity = rgb2lum(this.rgb);
this.style.color = luminosity > 186 ? "#000" : "#FFF";
}
reset_color = function(obj, color) {
obj.value = color;
obj.style.backgroundColor = color;
obj.rgb = obj.style.backgroundColor;
}
reset_dmenu_colors = function() {
reset_color(document.getElementById('.dmenu-foreground'), "#bbbbbb");
reset_color(document.getElementById('.dmenu-background'), "#222222");
reset_color(document.getElementById('.dmenu-selforeground'), "#eeeeee");
reset_color(document.getElementById('.dmenu-selbackground'), "#005577");
reset_color(document.getElementById('.dmenu-outforeground'), "#000000");
reset_color(document.getElementById('.dmenu-outbackground'), "#00ffff");
var colorpicks = document.getElementsByClassName('colorpick');
for(i = 0; i < colorpicks.length; i++){
colorpicks[i].dispatchEvent(new Event("change"));
}
};
reset_dmenu_colors();
document.getElementById('dmenu_reset_colors').onclick = reset_dmenu_colors;
var colorpicks = document.getElementsByClassName('colorpick');
lastfocused = colorpicks[0];
lastfocused.parentElement.classList.toggle("lastfocused");
for(i = 0; i < colorpicks.length; i++){
colorpicks[i].onfocus = function() { lastfocused.parentElement.classList.toggle("lastfocused"); lastfocused = this; lastfocused.parentElement.classList.toggle("lastfocused"); };
colorpicks[i].onchange = updateCSS;
colorpicks[i].dispatchEvent(new Event("change"));
}
var colorpickboxes = document.getElementsByClassName('colorpickbox');
for(i = 0; i < colorpickboxes.length; i++){
colorpickboxes[i].onclick = function() { this.children[0].focus=true; this.children[0].dispatchEvent(new Event("focus")); } ;
}
function download(filename, text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
export_xr_file = function(){
colorpicks = document.getElementsByClassName('colorpick');
var output_str = "!------- Custom Theme by Theme-o-matic --------\n"
for(i = 0; i < colorpicks.length; i++){
output_str += colorpicks[i].id.replace(".","").replace("-",".") + ": " + colorpicks[i].value + "\n"
}
download("theme-o-matic.xr", output_str);
}
xr_export_btn = document.getElementById('xr_export');
xr_export_btn.onclick = export_xr_file;
switchTabs = function(){
tabs = document.getElementsByClassName("colorpicktab")
tabnames = document.getElementsByClassName("colorpicktabname")
for(i=0; i < tabs.length; i++){
if(tabs[i].id == (this.innerHTML + "-tab")){
tabs[i].style.display = "block";
tabnames[i].classList.add("colorpicktabname-active");
lastfocused.parentElement.classList.toggle("lastfocused");
lastfocused = tabs[i].getElementsByClassName('colorpick')[0];
lastfocused.parentElement.classList.toggle("lastfocused");
} else{
tabs[i].style.display = "none";
tabnames[i].classList.remove("colorpicktabname-active");
}
}
}
tabs = document.getElementsByClassName("colorpicktab")
tabs[0].style.display = "block";
tabnames = document.getElementsByClassName("colorpicktabname")
tabnames[0].classList.toggle("colorpicktabname-active");
for(i=0; i < tabnames.length; i++){
tabnames[i].onclick = switchTabs;
}
//allevents = Object.keys(document.__proto__.__proto__).reduce((arr, event)=> {
// if(event.startsWith('on')) return [...arr, event.substr(2)];
// return arr;
//}, [])
//allevents.forEach(e => custom_color.addEventListener(e, function(event){console.log(event.type)}))
custom_color = document.getElementById("custom_color");
custom_color.onchange = function(){
lastfocused.value = this.value;
lastfocused.dispatchEvent(new Event("change"));
};
img = document.getElementById('output_image');
img.addEventListener('load', function() {
makePalette(colorThief.getPalette(img, 20,5))
});
//Backgroun setting buttons
document.getElementById("scale").onclick = function(){ document.getElementById("output_image").style.objectFit = "cover"; };
document.getElementById("stretch").onclick = function(){ document.getElementById("output_image").style.objectFit = "fill"; };
document.getElementById("center").onclick = function(){ document.getElementById("output_image").style.objectFit = "none"; };
</script>
</html>