krz/palettes

A color palette generator with export utilities.

clone: git clone https://gitbay.org/krz/palettes.git

main: assets/js/app.js · raw

  1function getRGB() {
  2	var r = Math.floor(Math.random() * 255);
  3	var g = Math.floor(Math.random() * 255);
  4	var b = Math.floor(Math.random() * 255);
  5	return [r, g, b];
  6}
  7
  8function getHex(rgb) {
  9	var hex = "";
 10	rgb.forEach(function (val) {
 11		var hexPartial = Number(val).toString(16);
 12		if (hexPartial.length < 2) {
 13			hexPartial = "0" + hexPartial;
 14		}
 15		hex = hex + hexPartial;
 16	});
 17	return hex;
 18}
 19
 20function getCMYK(rgb) {
 21	var finalK = 0;
 22
 23	var r = rgb[0];
 24	var g = rgb[1];
 25	var b = rgb[2];
 26
 27	if (r === 0 && g === 0 && b === 0) {
 28		finalK = 1;
 29		return [0, 0, 0, 1];
 30	}
 31
 32	var finalC = 1 - r / 255;
 33	var finalM = 1 - g / 255;
 34	var finalY = 1 - b / 255;
 35
 36	var minCMY = Math.min(finalC, Math.min(finalM, finalY));
 37	finalC = Math.trunc(((finalC - minCMY) / (1 - minCMY)) * 100);
 38	finalM = Math.trunc(((finalM - minCMY) / (1 - minCMY)) * 100);
 39	finalY = Math.trunc(((finalY - minCMY) / (1 - minCMY)) * 100);
 40	finalK = Math.trunc(minCMY * 100);
 41
 42	return finalC + "," + finalM + "," + finalY + "," + finalK;
 43}
 44
 45function getContrast(rgb) {
 46	return (299 * rgb[0] + 587 * rgb[1] + 114 * rgb[2]) / 1000;
 47}
 48
 49function generate(elements) {
 50	elements.each(function (index, column) {
 51		let rgb = getRGB();
 52		$(column).find(".color-rgb").text(`(${rgb})`);
 53		$(column)
 54			.find(".color-hex")
 55			.text("#" + getHex(rgb));
 56		$(column)
 57			.find(".color-cmyk")
 58			.text(`(${getCMYK(rgb)})`);
 59		$(column).css("background-color", `rgb(${rgb})`);
 60		if (getContrast(rgb) < 123) {
 61			$(column).addClass("text-white");
 62		} else {
 63			$(column).removeClass("text-white");
 64		}
 65	});
 66}
 67
 68function regenerate() {
 69	generate($(".color-column[data-locked='false']"));
 70}
 71
 72function copy(type, text) {
 73	var $tempTextField = $("<input>");
 74	$("body").append($tempTextField);
 75	switch (type) {
 76		case "rgb":
 77			$tempTextField.val("rgb" + text).select();
 78			break;
 79		case "hex":
 80			$tempTextField.val(text).select();
 81			break;
 82		case "cmyk":
 83			$tempTextField.val("cmyk" + text).select();
 84			break;
 85	}
 86	document.execCommand("copy");
 87	$tempTextField.remove();
 88}
 89
 90function showToast(type, text) {
 91	var alert =
 92		"<div class='toast-alert alert alert-" +
 93		type +
 94		"' role='alert'>" +
 95		text +
 96		"</div>";
 97	$(".container-fluid").append(alert);
 98	$(".toast-alert").animate(
 99		{
100			opacity: 0,
101		},
102		2000,
103		function () {
104			$(this).remove();
105		}
106	);
107}
108
109function init() {
110	regenerate();
111
112	$(".color-value").click(function (e) {
113		var text = $(e.target).text();
114		copy($(e.target).data("format"), text);
115		showToast("success", "Color code copied to clipboard.");
116	});
117
118	$(".color-column-lock").click(function (e) {
119		var icon = $(e.target);
120		var column = $(e.target).parent().parent();
121		var status = column.attr("data-locked");
122		if (status === "true") {
123			column.attr("data-locked", "false");
124		} else {
125			column.attr("data-locked", "true");
126		}
127		icon.toggleClass(["fa-lock-open", "fa-lock"]);
128	});
129
130	$(".color-column-regenerate").click(function (e) {
131		generate($(e.target).parent().parent());
132	});
133
134	$("#submitNewColor").click(function (e) {
135		setNewColor(getNewColor(e));
136	});
137
138	loadAllPalettes();
139}
140
141function setNewColor(values) {
142	var column = $(".color-column:eq(" + (parseInt(values[1]) - 1) + ")");
143	var rgb = JSON.parse("[" + values[0] + "]");
144	$(column).find(".color-rgb").text(`(${rgb})`);
145	$(column)
146		.find(".color-hex")
147		.text("#" + getHex(rgb));
148	$(column)
149		.find(".color-cmyk")
150		.text(`(${getCMYK(rgb)})`);
151	$(column).css("background-color", `rgb(${rgb})`);
152	if (getContrast(rgb) < 123) {
153		$(column).addClass("text-white");
154	} else {
155		$(column).removeClass("text-white");
156	}
157}
158
159function getNewColor(e) {
160	var string = $(e.target).closest(".modal-content").find("input").val();
161	var newString = string.replace("(", "").replace(")", "").replace("rgb", "");
162	var column = $(e.target)
163		.closest(".modal-content")
164		.find("select option:selected")
165		.text();
166	return [newString, column];
167}
168
169function switchTheme() {
170	$("body").toggleClass("custom-bg");
171	$(".fa-moon").toggleClass("d-none");
172	$(".fa-sun").toggleClass("d-none");
173	$(".color-column-labels").toggleClass("text-white");
174}
175
176function storePalette(keysObject, paletteName) {
177	// Query object of all rgb colors and store text values in new object
178	var rgbDOMObject = $(".color-rgb");
179	var rgbStorageObject = {
180		0: $(rgbDOMObject[0]).text().replace("(", "").replace(")", ""),
181		1: $(rgbDOMObject[1]).text().replace("(", "").replace(")", ""),
182		2: $(rgbDOMObject[2]).text().replace("(", "").replace(")", ""),
183		3: $(rgbDOMObject[3]).text().replace("(", "").replace(")", ""),
184		4: $(rgbDOMObject[4]).text().replace("(", "").replace(")", ""),
185	};
186	// Generate random key, ensure it doesn't exist already, then save the key in storage
187	var randomKey = generateRandomKey();
188	if (keysObject === null) {
189		var newKeysObject = {};
190		newKeysObject[paletteName] = randomKey;
191	} else {
192		var newKeysObject = keysObject;
193		newKeysObject[paletteName] = randomKey;
194	}
195	localStorage.setItem("paletteKeys", JSON.stringify(newKeysObject));
196	// Save color palette object
197	localStorage.setItem(randomKey, JSON.stringify(rgbStorageObject));
198
199	return randomKey;
200}
201
202function savePalette() {
203	// Get palette names object and user input of new palette name
204	var keysObject = JSON.parse(localStorage.getItem("paletteKeys"));
205	var paletteName = $("#inputPaletteName").val();
206	var nameCheck = false;
207	// Check palette name exists
208	if (keysObject !== null && paletteName in keysObject) {
209		nameCheck = true;
210	}
211	if (typeof Storage !== "undefined") {
212		// If the input name is null or empty, show an error alert
213		if (
214			paletteName === null ||
215			paletteName == "undefined" ||
216			paletteName == ""
217		) {
218			alert("Error: You must enter a valid name for this palette.");
219		} else if (keysObject != null && nameCheck === true) {
220			// If the name exists, ask user to confirm
221			var userConfirmation = confirm(
222				"Palette name exists. Do you want to overwrite this palette?"
223			);
224			// If the user confirms, save the palette
225			if (userConfirmation) {
226				var randomKey = storePalette(keysObject, paletteName);
227				$("#savedPalettesBody").append(
228					"<button class='btn btn-outline-secondary my-2 w-100' onclick='loadPalette(" +
229						randomKey +
230						")'>" +
231						paletteName +
232						"</button>"
233				);
234				showToast("success", "Color palette saved.");
235			}
236		} else {
237			// If the name doesn't exist, save palette
238			var randomKey = storePalette(keysObject, paletteName);
239			$("#savedPalettesBody").append(
240				"<div id='" +
241					randomKey +
242					"' class='my-2 d-flex'><div class='btn-group w-100' role='group' aria-label='Saved palette'><button class='btn btn-secondary w-100' onclick='loadPalette(" +
243					randomKey +
244					")'>" +
245					paletteName +
246					"</button><button class='btn btn-danger' onclick='deletePalette(" +
247					randomKey +
248					")'><i class='far fa-trash-alt'></i></button></div></div>"
249			);
250			showToast("success", "Color palette saved.");
251		}
252	} else {
253		alert(
254			"Sorry, your browser does not support Web Storage. Please ugrade your browser and try again."
255		);
256	}
257}
258
259function loadAllPalettes() {
260	if (typeof Storage !== "undefined") {
261		var fetchedData = localStorage.getItem("paletteKeys");
262		if (fetchedData === null) {
263			console.log("Warning: No palettes exist.");
264		} else {
265			$.each(JSON.parse(fetchedData), function (key, value) {
266				var palette = localStorage.getItem(key);
267				$("#savedPalettesBody").append(
268					"<div id='" +
269						value +
270						"' class='my-2 d-flex'><div class='btn-group w-100' role='group' aria-label='Saved palette'><button class='btn btn-secondary w-100' onclick='loadPalette(" +
271						value +
272						")'>" +
273						key +
274						"</button><button class='btn btn-danger' onclick='deletePalette(" +
275						value +
276						")'><i class='far fa-trash-alt'></i></button></div></div>"
277				);
278				$("#editColorModal").modal("hide");
279			});
280			showToast("success", "Color palettes loaded.");
281		}
282	} else {
283		alert(
284			"Sorry, your browser does not support Web Storage. Please ugrade your browser and try again."
285		);
286	}
287}
288
289function loadPalette(requestedKey) {
290	var fetchedData = localStorage.getItem("paletteKeys");
291	$.each(JSON.parse(fetchedData), function (key, value) {
292		var newValue = parseInt(value, 10);
293		if (requestedKey === newValue) {
294			var palette = localStorage.getItem(value);
295			$.each(JSON.parse(palette), function (subKey, subValue) {
296				var col = parseInt(subKey, 10) + 1;
297				setNewColor([subValue, col]);
298			});
299		}
300		$("#editColorModal").modal("hide");
301	});
302}
303
304function deleteAllPalettes() {
305	var confirmation = confirm("Are you sure you want to delete all palettes?");
306	if (confirmation) {
307		$("#savedPalettesBody button").remove();
308		localStorage.clear();
309	}
310}
311
312function deletePalette(id) {
313	var confirmation = confirm("Are you sure you want to delete this palette?");
314	if (confirmation) {
315		// Get name of palette by the id
316		var keysObject = JSON.parse(localStorage.getItem("paletteKeys"));
317		var name = getKeyByValue(keysObject, id);
318		// Remove the button
319		$("#" + id).remove();
320		// Remove local storage item
321		localStorage.removeItem(id);
322		// Remove item from paletteKeys
323		delete keysObject[name];
324		// Set new paletteKeys object
325		var newKeysObject = keysObject;
326		localStorage.setItem("paletteKeys", JSON.stringify(newKeysObject));
327	}
328}
329
330function generateRandomKey() {
331	// Generate random key
332	var randomKey = Math.floor(Math.random() * 9007199254740992 + 1);
333	// Check if random key exists (up to 100 times)
334	for (var i = 0; i < 100; i++) {
335		// If the key exists, generate a new key
336		if (checkKey(randomKey) === true) {
337			randomKey = Math.floor(Math.random() * 9007199254740992 + 1);
338		}
339		// If the key does not exist, break the loop and return the key
340		else {
341			break;
342		}
343	}
344	return randomKey;
345}
346
347function checkKey(key) {
348	// Fetch paletteKeys object
349	var keysObject = localStorage.getItem("paletteKeys");
350	// If object is null, it doesn't exist yet
351	if (keysObject !== null) {
352		// If object exists, parse it and check to see if the key exists
353		var tempObject = JSON.parse(keysObject);
354		if (tempObject.hasOwnProperty(key.toString())) {
355			return true;
356		} else {
357			return false;
358		}
359	}
360}
361
362function saveImage() {
363	// Remove previous image
364	$("#saveImageModal img").remove();
365	// Hide toolbar so it doesn't appear in screenshot
366	$(".color-column-toolbar").hide();
367	// Set background color of canvas based on body
368	var bgColor = $("body").hasClass("custom-bg") ? "#000000" : "#FFFFFF";
369	// Get canvas and launch modal
370	html2canvas(document.getElementsByClassName("container-fluid")[0], {
371		backgroundColor: bgColor,
372	}).then(function (canvas) {
373		$(".color-column-toolbar").show();
374		var img = canvas.toDataURL("image/png");
375		$("#saveImageModal").modal("show");
376		$("#saveImageModal .modal-body").append(
377			'<img id="palette-image" class="img-fluid" src="' + img + '"/>'
378		);
379	});
380}
381
382function getKeyByValue(object, value) {
383	for (var i = 0; i < Object.keys(object).length; i++) {
384		var key = Object.keys(object)[i];
385		var fetchedValue = object[key];
386		if (value === fetchedValue) {
387			return key;
388		}
389	}
390}