Skip to content

Commit 3c8e1b0

Browse files
feat: Add simple color converter toool
1 parent 596be77 commit 3c8e1b0

File tree

4 files changed

+217
-0
lines changed

4 files changed

+217
-0
lines changed

simple-color-converter/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Simple Color converter
2+
> Simple CSS color converter tool from RGB to hex and vice-versa
3+
4+
## To run
5+
- No config needed. Start a HTTP server in the current directory
6+
- You can run the following command provided you have `node`, `npx` installed
7+
8+
``` shell
9+
npx serve -p 8080
10+
```
11+
- Open [http://localhost:8080](http://localhost:8080) to see the changed
12+
13+
## Screenshots
14+
15+
16+
## Contribute
17+
Change UI, play around, tweak as you like.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
body {
2+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
3+
background-color: #121212;
4+
color: white;
5+
text-align: center;
6+
align-items: center;
7+
}
8+
9+
.container .main-app-container .input-container {
10+
display: flex;
11+
margin: 0 20%;
12+
justify-content: space-around;
13+
}
14+
15+
.container .main-app-container .input-container .mode-dropdown-container .mode-dropdown {
16+
width: 150px;
17+
height: 40px;
18+
border-radius: 5px;
19+
}
20+
21+
.container .main-app-container input {
22+
width: 200px;
23+
height: 30px;
24+
border: 1px solid #333;
25+
border-radius: 5px;
26+
padding: 5px;
27+
}
28+
29+
.container .main-app-container .input-container .convert-button-container button {
30+
width: 100px;
31+
height: 40px;
32+
border: 1px solid #333;
33+
cursor: pointer;
34+
border-radius: 5px;
35+
}

simple-color-converter/index.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<link rel ="stylesheet" href="css/style.css">
7+
<title>Color Converter</title>
8+
</head>
9+
<body>
10+
<div class="container">
11+
<h1>Color Converter</h1>
12+
<div class="main-app-container">
13+
<div class="input-container"></div>
14+
<div class="output-container"></div>
15+
</div>
16+
</div>
17+
<script src="js/index.js"></script>
18+
</body>
19+
</html>

simple-color-converter/js/index.js

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
const MODES = {
2+
RGB_TO_HEX: 'RGB to HEX',
3+
HEX_TO_RGB: 'HEX to RGB'
4+
};
5+
6+
let selectedMode = MODES.RGB_TO_HEX;
7+
8+
function modeChangeHandler(event) {
9+
const newMode = event.target.value;
10+
if (selectedMode === newMode) return;
11+
12+
selectedMode = newMode;
13+
14+
const inputContainer = document.querySelector('.input-container');
15+
const oldInputsContainer = inputContainer.querySelector('.mode-inputs-container');
16+
if (oldInputsContainer) {
17+
inputContainer.removeChild(oldInputsContainer);
18+
}
19+
20+
renderModeInputs(inputContainer, selectedMode);
21+
}
22+
23+
function renderModeDropdown(container) {
24+
const divElement = document.createElement('div');
25+
divElement.className = 'mode-dropdown-container';
26+
container.appendChild(divElement);
27+
28+
const dropdownLabel = document.createElement('label');
29+
dropdownLabel.textContent = 'Select Conversion Mode: ';
30+
dropdownLabel.setAttribute('for', 'mode-dropdown');
31+
32+
const modeDropdown = document.createElement('select');
33+
modeDropdown.className = 'mode-dropdown';
34+
modeDropdown.addEventListener('change', modeChangeHandler);
35+
36+
Object.values(MODES).forEach(mode => {
37+
const option = document.createElement('option');
38+
option.value = mode;
39+
option.textContent = mode;
40+
if (mode === selectedMode) {
41+
option.selected = true;
42+
}
43+
modeDropdown.appendChild(option);
44+
});
45+
46+
divElement.appendChild(dropdownLabel);
47+
divElement.appendChild(modeDropdown);
48+
}
49+
50+
function renderModeInputs(container, mode) {
51+
const inputsContainer = document.createElement('div');
52+
inputsContainer.className = 'mode-inputs-container';
53+
container.appendChild(inputsContainer);
54+
55+
if (mode === MODES.RGB_TO_HEX) {
56+
['R', 'G', 'B'].forEach(label => {
57+
const input = document.createElement('input');
58+
input.type = 'number';
59+
input.placeholder = `${label} (0-255)`;
60+
input.min = 0;
61+
input.max = 255;
62+
input.style.width = '80px';
63+
inputsContainer.appendChild(input);
64+
});
65+
} else if (mode === MODES.HEX_TO_RGB) {
66+
const hexInput = document.createElement('input');
67+
hexInput.type = 'text';
68+
hexInput.placeholder = 'HEX (#RRGGBB)';
69+
inputsContainer.appendChild(hexInput);
70+
}
71+
}
72+
73+
function renderConvertButton(inputContainer) {
74+
const convertButtonDiv = document.createElement('div');
75+
convertButtonDiv.className = 'convert-button-container';
76+
inputContainer.appendChild(convertButtonDiv);
77+
78+
const convertButton = document.createElement('button');
79+
convertButton.textContent = 'Convert';
80+
convertButton.addEventListener('click', renderOutput);
81+
82+
convertButtonDiv.appendChild(convertButton);
83+
}
84+
85+
function renderOutput() {
86+
const outputContainer = document.querySelector('.output-container');
87+
outputContainer.style.marginTop = '20px';
88+
outputContainer.innerHTML = '';
89+
90+
const inputContainer = document.querySelector('.input-container');
91+
const inputsContainer = inputContainer.querySelector('.mode-inputs-container');
92+
const inputs = inputsContainer.querySelectorAll('input');
93+
94+
let outputText = '';
95+
96+
if (selectedMode === MODES.RGB_TO_HEX) {
97+
const r = parseInt(inputs[0].value);
98+
const g = parseInt(inputs[1].value);
99+
const b = parseInt(inputs[2].value);
100+
101+
if (
102+
isNaN(r) || r < 0 || r > 255 ||
103+
isNaN(g) || g < 0 || g > 255 ||
104+
isNaN(b) || b < 0 || b > 255
105+
) {
106+
outputText = 'Invalid RGB values. Please enter numbers between 0 and 255.';
107+
} else {
108+
outputText = `HEX: #${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`;
109+
}
110+
} else if (selectedMode === MODES.HEX_TO_RGB) {
111+
const hex = inputs[0].value.trim();
112+
const hexRegex = /^#?([a-fA-F0-9]{6})$/;
113+
114+
if (!hexRegex.test(hex)) {
115+
outputText = 'Invalid HEX value. Please enter a valid HEX color code.';
116+
} else {
117+
const hexValue = hex.startsWith('#') ? hex.slice(1) : hex;
118+
const r = parseInt(hexValue.slice(0, 2), 16);
119+
const g = parseInt(hexValue.slice(2, 4), 16);
120+
const b = parseInt(hexValue.slice(4, 6), 16);
121+
122+
outputText = `RGB: ${r}, ${g}, ${b}`;
123+
}
124+
}
125+
126+
outputContainer.textContent = outputText;
127+
document.body.style.backgroundColor = selectedMode === MODES.RGB_TO_HEX
128+
? `rgb(${inputs[0].value || 0}, ${inputs[1].value || 0}, ${inputs[2].value || 0})`
129+
: inputs[0].value || '#ffffff';
130+
131+
// Set text color based on background brightness
132+
document.body.style.color = selectedMode === MODES.RGB_TO_HEX
133+
? (parseInt(inputs[0].value) + parseInt(inputs[1].value) + parseInt(inputs[2].value) > 382 ? 'black' : 'white')
134+
: (parseInt(hexValue.slice(0, 2), 16) + parseInt(hexValue.slice(2, 4), 16) + parseInt(hexValue.slice(4, 6), 16) > 382 ? 'black' : 'white');
135+
}
136+
137+
function main() {
138+
const mainAppContainer = document.querySelector('.main-app-container');
139+
const inputContainer = mainAppContainer.querySelector('.input-container');
140+
141+
renderModeDropdown(inputContainer);
142+
renderConvertButton(inputContainer);
143+
renderModeInputs(inputContainer, selectedMode);
144+
}
145+
146+
document.addEventListener('DOMContentLoaded', main);

0 commit comments

Comments
 (0)